Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
adding a delay on end
#1
Noob here.

I've been trying to set up a simple code to operate two relays.
Relay 1 is to turn on a router.
Relay 2 is to turn on a vacuum.
This is a cnc.

The input is from a CNC controller with a 5v dc output.
I am using a 5V dc relay as an interface.

Here is the code I did.
What i would like, is the Relay 1 to start straight away with a 5 second dlay for Relay 2.
when the input stops, the Relay 1 can stop but i would like the Relay 2 to run on for 10 seconds to clear the debri.

# import GPIO and Time

import time
import RPi.GPIO as GPIO

#set GPIO numbering mode and define outputs
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT) #router
GPIO.setup(25, GPIO.OUT) #LED lighting
GPIO.setup(24, GPIO.OUT) #vacuum
GPIO.setup(16, GPIO.OUT) #camera
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP) #input from cnc

# cycle those relays
try:
    while True:
        if (GPIO.input(5))== False: # cnc program is started
            GPIO.output(23,True) # Router is on
            print("router is on")
            time.sleep(5) # delay starting the vacuum
            GPIO.output(24,True) # vacuum is now on 
            print("vacuum is on")
        elif (GPIO.input(5))== True: # cnc program has stopped
            GPIO.output(23,False) # stopping router
            print ("router is off")
            time.sleep(10)
            GPIO.output(24,False) # vacuum is now off
            print ("Vacuum is off")
            time.sleep(1)
        
        
finally:
# cleanup the GPIO before finishing
    GPIO.cleanup()
I'm having issues with the times being out.
Yoriz write Sep-28-2021, 11:10 AM:
Please post all code, output and errors (in their entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
Controller programs should never sleep. If you hit the switch for your CNC and decide to turn it off, do you want the router to run for 10 seconds? Instead of sleeping your program should set a schedule for when things should happen.

I don't know if Python for raspberry pi has the schedule library, so this is an example that uses the time() library. It has an Output class which represents a device that you control using GPIO.output. This device may have a startup delay and a shutdown delay. When you start the device it delays for the startup delay then sets the output to True. When you stop the device it delays for the shutdown delay and sets the output to False. The advantage of this class over using sleep is that it is not blocking the program while this waiting occurs. If you quick turn off the CNC after turning it on, your program can tell the router and vacuum to turn off immediately.

# import GPIO and Time

import time
import RPi.GPIO as GPIO

# Output states
OFF = 0       # Is off
ON = 1        # Is on
STARTING = 2  # Will turn on after startup delay
STOPPING = 3  # Will turn off after shutdown delay

CNC_STATUS = 5

class Output():
    '''Output controller.  Has a delay for turning on and off'''
    def __init__(self, id, pin, on_delay=0, off_delay=0):
        self.id = id               # Name I use when printing
        self.pin = pin             # Output pin number
        self.state = OFF           # Initialial state
        self.on_delay = on_delay   # Startup delay
        self.off_delay = off_delay # shutdown delay
        self.delay = None
        GPIO.setup(pin, GPIO_OUT)

    def start(self):
        '''Turn me on.  There may be a short delay'''
        if self.state is OFF:
            # I need to start
            self.delay = time.time() + self.on_delay  # When I will turn on
            self.state = STARTING
            print(self.id, 'is starting')
        elif self.state is not STARTING:
            # I was already on
            self.state = ON

    def stop(self):
        '''Turn me off.  There may be a short delay'''
        if self.state is ON:
            # I need to stop
            self.delay = time.time() + self.off_delay # When I will turn off
            self.state = STOPPING
        elif self.state is not STOPPING:
            # I was already off
            self.state = OFF

    def update(self):
        '''Check if delay time has expired.  set pin out'''
        if self.state in (STARTING, STOPPING):
            if time.time() > self.delay:
                self.state = ON if self.state == STARTING else OFF
                GPIO.ouput(self.pin, (True, False)[self.state])
                print(self.id, 'is', ('On', 'Off')[self.state])


#set GPIO numbering mode and define outputs
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
router = Output('router', 23, 0, 0)
vacuum = Output('vaccum', 24, 5, 10)
PIO.setup(CNC_STATUS, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# cycle those relays
try:
    cnc_on = None
    while True:
        # Check if the cnc state has changed
        status = not GPIO.input(CNC_STATUS)
        if status != cnc_on:
            cnc_on = status
            if cnc_on:
                router.start()
                vacuum.start()
            else:
                router.stop()
                vacuum.stop()
        router.update()
        vacuum.update()
finally:
    # I guess we exit out with an exception?  Turn everything off but wait for vacuum to shut down.
    router.stop()
    vacuum.stop()
    while vacuum.state is not OFF:
        vacuum.update()
    # cleanup the GPIO before finishing
    GPIO.cleanup()

I like this arrangement better. Instead of making the delay an attribute of the output, I made it an optional argument when setting the output.
vacuum.output(True, 5) will set GPIO.output(24, False) five seconds from now.

I also modified the class to keep a list of outputs waiting to be set. When you call GPIO_Output.output() with a non-zero delay, the object is added to the class wait list. The application should periodically call GPIO_Output.update to process the list. When an GPIO_Output object's delay time expires, the output is set and the object is removed from the wait list.
# import GPIO and Time

import time
import RPi.GPIO as GPIO

class GPIO_Output():
    '''GPIO output with delay.  If you specify a delay when turning
    me on or off, I delay that many seconds before setting the output
    '''
    wait_list = []  # List of outputs waiting to be set

    @classmethod
    def update(cls):
        '''Update wait_list.  Return True if list not empty'''
        cls.wait_list = [x for x in cls.wait_list if not x.done()]
        return len(cls.wait_list) > 0

    def __init__(self, pin, on=False):
        self.pin = pin
        self.on = on
        self.new_state = on
        self.delay = None
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, on)

    def output(self, on, delay=0):
        '''Set output.  Can specify optional delay (in seconds) to wait before setting output'''
        if self.on == on:
            self.delay = None  # Stop pending change
        elif delay > 0:
            self.new_state = on  # Schedule a change
            self.delay = time.time() + delay
            self.wait_list.append(self)
        else:
            self.on = on  # Set output immediately
            self.delay = None
            GPIO.output(self.pin, self.on)

    def done(self):
        '''Set output when delay expires.  Return True if wait is over'''
        if self.delay and time.time() >= self.delay:
            self.delay = None
            self.on = self.new_state
            GPIO.ouput(self.pin, self.on)
        return self.delay is None

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
router = GPIO_Output('router', 23)
vacuum = GPIO_Output('vaccum', 24)
CNC_STATUS = 5
GPIO.setup(CNC_STATUS, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# cycle those relays
try:
    while True:
        # Check if the cnc state has changed
        cnc_on = not GPIO.input(CNC_STATUS)
        if cnc_on != router.on:
            router.output(cnc_on)
            vacuum.output(cnc_on, 5 if cnc_on else 10)
        GPIO_Output.udpate()
finally:
    # I guess we exit out with an exception?  Turn stuff off and wait for vacuum to shut down.
    router.output(False)
    vacuum.output(False, 10)
    while GPIO_Output.update():
        pass
    GPIO.cleanup()
Reply
#3
(Sep-28-2021, 09:50 PM)deanhystad Wrote: I like this arrangement better. Instead of making the delay an attribute of the output, I made it an optional argument when setting the output.
vacuum.output(True, 5) will set GPIO.output(24, False) five seconds from now.

I also modified the class to keep a list of outputs waiting to be set. When you call GPIO_Output.output() with a non-zero delay, the object is added to the class wait list. The application should periodically call GPIO_Output.update to process the list. When an GPIO_Output object's delay time expires, the output is set and the object is removed from the wait list.
# import GPIO and Time

import time
import RPi.GPIO as GPIO

class GPIO_Output():
    '''GPIO output with delay.  If you specify a delay when turning
    me on or off, I delay that many seconds before setting the output
    '''
    wait_list = []  # List of outputs waiting to be set

    @classmethod
    def update(cls):
        '''Update wait_list.  Return True if list not empty'''
        cls.wait_list = [x for x in cls.wait_list if not x.done()]
        return len(cls.wait_list) > 0

    def __init__(self, pin, on=False):
        self.pin = pin
        self.on = on
        self.new_state = on
        self.delay = None
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, on)

    def output(self, on, delay=0):
        '''Set output.  Can specify optional delay (in seconds) to wait before setting output'''
        if self.on == on:
            self.delay = None  # Stop pending change
        elif delay > 0:
            self.new_state = on  # Schedule a change
            self.delay = time.time() + delay
            self.wait_list.append(self)
        else:
            self.on = on  # Set output immediately
            self.delay = None
            GPIO.output(self.pin, self.on)

    def done(self):
        '''Set output when delay expires.  Return True if wait is over'''
        if self.delay and time.time() >= self.delay:
            self.delay = None
            self.on = self.new_state
            GPIO.ouput(self.pin, self.on)
        return self.delay is None

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
router = GPIO_Output('router', 23)
vacuum = GPIO_Output('vaccum', 24)
CNC_STATUS = 5
GPIO.setup(CNC_STATUS, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# cycle those relays
try:
    while True:
        # Check if the cnc state has changed
        cnc_on = not GPIO.input(CNC_STATUS)
        if cnc_on != router.on:
            router.output(cnc_on)
            vacuum.output(cnc_on, 5 if cnc_on else 10)
        GPIO_Output.udpate()
finally:
    # I guess we exit out with an exception?  Turn stuff off and wait for vacuum to shut down.
    router.output(False)
    vacuum.output(False, 10)
    while GPIO_Output.update():
        pass
    GPIO.cleanup()

Thankyou Dean

looks like i have a lot to learn.

I copied and past this one to the Pi ran the code and received this error.

Error:
">>> %Run 'cnc 4 relay control.py' Traceback (most recent call last): File "/home/pi/Python Files/cnc 4 relay control.py", line 49, in <module> router = GPIO_Output('router', 23) File "/home/pi/Python Files/cnc 4 relay control.py", line 23, in __init__ GPIO.setup(pin, GPIO.OUT) ValueError: Channel must be an integer or list/tuple of integers "
Yoriz write Sep-29-2021, 05:19 AM:
Please post all code, output and errors (in their entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#4
I suspect lines 49 and 50 should not have the string there, but be more like: router = GPIO_Output(23).
Reply
#5
Inter-version-itis and no raspberry pi or GPIO library. Still sloppy and emberassing.
Reply
#6
Thank you all very much did the changes and it looks great.

# import GPIO and Time
 
import time
import RPi.GPIO as GPIO
 
class GPIO_Output():
    '''GPIO output with delay.  If you specify a delay when turning
    me on or off, I delay that many seconds before setting the output
    '''
    wait_list = []  # List of outputs waiting to be set
 
    @classmethod
    def update(cls):
        '''Update wait_list.  Return True if list not empty'''
        cls.wait_list = [x for x in cls.wait_list if not x.done()]
        return len(cls.wait_list) > 0
 
    def __init__(self, pin, on=False):
        self.pin = pin
        self.on = on
        self.new_state = on
        self.delay = None
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, on)
 
    def output(self, on, delay=0):
        '''Set output.  Can specify optional delay (in seconds) to wait before setting output'''
        if self.on == on:
            self.delay = None  # Stop pending change
        elif delay > 0:
            self.new_state = on  # Schedule a change
            self.delay = time.time() + delay
            self.wait_list.append(self)
        else:
            self.on = on  # Set output immediately
            self.delay = None
            GPIO.output(self.pin, self.on)
 
    def done(self):
        '''Set output when delay expires.  Return True if wait is over'''
        if self.delay and time.time() >= self.delay:
            self.delay = None
            self.on = self.new_state
            GPIO.ouput(self.pin, self.on)
        return self.delay is None
 
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
router = GPIO_Output(23)
vacuum = GPIO_Output(24)
CNC_STATUS = 5
GPIO.setup(CNC_STATUS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
 
# cycle those relays
try:
    while True:
        # Check if the cnc state has changed
        cnc_on = not GPIO.input(CNC_STATUS)
        if cnc_on != router.on:
            router.output(cnc_on)
            vacuum.output(cnc_on, 5 if cnc_on else 10)
        GPIO_Output.update()
finally:
    # I guess we exit out with an exception?  Turn stuff off and wait for vacuum to shut down.
    router.output(False)
    vacuum.output(False, 10)
    while GPIO_Output.update():
        pass
    GPIO.cleanup()
Yoriz write Sep-29-2021, 05:20 AM:
Please post all code, output and errors (in their entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#7
You got 2 free passes from Yoriz. Next time you want help please wrap your code in Python tags (All it takes is a button press). If you are too lazy to properly format your posts I'll be too lazy to read them.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Is it possible to add a delay right after a request.get() cubangt 6 2,349 Sep-07-2023, 09:29 AM
Last Post: shoesinquiry
  Request Delay pheadrus 1 3,711 Nov-25-2021, 08:51 PM
Last Post: snippsat
  python delay without interrupt the whole code Nick_tkinter 4 5,054 Feb-22-2021, 10:51 PM
Last Post: nilamo
  How to read CSV file one row at the time in a range and some delay in between greenpine 2 4,673 Nov-20-2020, 02:26 PM
Last Post: greenpine
  configure delay on only one link using python3 HiImAl 3 2,666 Oct-21-2020, 07:51 PM
Last Post: buran
  Keyboard commands and delay/latency RungJa 0 2,093 Mar-29-2020, 01:28 PM
Last Post: RungJa
  Adding markers to Folium map only adding last element. tantony 0 2,095 Oct-16-2019, 03:28 PM
Last Post: tantony
  Unwanted delay between looped synth plays WolfeCreek 1 2,284 Aug-02-2018, 09:24 PM
Last Post: Vysero
  Vpython Delay in plotting points SohaibAJ 0 2,036 Jul-30-2018, 08:44 PM
Last Post: SohaibAJ
  PyAudio delay hast 1 5,169 Jan-23-2018, 09:19 PM
Last Post: j.crater

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020