Python Forum
Halting if command if gpio triggered event triggered
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Halting if command if gpio triggered event triggered
#1
I am tweaking this code to get it ready for full integration into an animatronics costume setup. The individual pieces work. basically the GPIO triggers are limit switches. I am trying to build things such that if things slip or move that it will move forward if I hit the forward or backward button again and stop once the limit switch is triggered.

The way the libraries are it appears that it will stop as it is running through a for I range loop but will backup once that loop finishes if the gpio gets triggered.

I will keep researching and will probably sleep on things after I spend all evening researching different approaches on this conundrum. I just need to chew on things but more minds can help come up with unexpected solutions.

This is the code:
#!/usr/bin/python

import cwiid
import RPi.GPIO as GPIO
import sys
from time import *
import subprocess
import board

#this is for stepper motor controls, keyboard initiates movement, Button is limit switches
import keyboard

#gpiozero is the only library I have found that functions with the current pi and hardware setup I am using
from gpiozero import Button

#these are part of the Blinka libraries Adafruit has.  
from adafruit_motorkit import MotorKit
from adafruit_motor import stepper
kit1 = MotorKit()

# this is for stepper motors and servo board
from board import SCL, SDA
import busio
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50

# standard servo declearations for controls
from adafruit_servokit import ServoKit
kit = ServoKit(channels=16)

#12 and 13 are for one motion assembly backing up one full turn
button12 = Button(12)
button13 = Button(13)
#27 and 5 are for the other motion assembly
button27 = Button(27)
button5 = Button(5)
# while True loops endlessly.  This can be run as a service using systemd or setup as an init.d script or as an rc.local script.
while True:

  if button12.is_pressed:
    print("button12 pressed")
    for i in range (200):
      kit1.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

  if button13.is_pressed:
    print("button13 pressed")
    for i in range (200):
      kit1.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)

  if keyboard.is_pressed('f'):
    print("f is pressed")
    for i in range (200):
      kit1.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

  if keyboard.is_pressed('b'):
    print("b is pressed")
    for i in range (200):
      kit1.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)

# This is for channel 2 stepper motor.  

  if button27.is_pressed:
    print("button12 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

  if button5.is_pressed:
    print("button13 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)

  if keyboard.is_pressed('r'):
    print("f is pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

  if keyboard.is_pressed('l'):
    print("b is pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
Reply
#2
OK I did some playing around and apparently I have to add a nested if statement with a break that calls back to detech the button press on the relevant gpio pin.

if keyboard.is_pressed('f'):
kit.servo[5].angle=10
print("f is pressed")
for I in range (3300):
  if button13.is_pressed:
    i = 3300
    break
  kit1.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)
if keyboard.is_pressed('b'):
kit.servo[5].angle=110
print("b is pressed")
for I in range (3300):
  if button12.is_pressed:
    i = 3300
    break
  kit1.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
The thing I have to account for is if the system starts up bound at the edge of travel with GPIO activated at either end.
Reply
#3
What is the 200 loop for? Why not just move the stepper as long as a button is pressed and stop when it is released?
Reply
#4
Only allow motion when the associated limit switch is not pressed.
stepper1 = None
stepper2 = None
while True:
    if keyboard.is_pressed('f') and not button12.is_pressed:
        stepper1 = stepper.BACKWARD

    elif keyboard.is_pressed('b') and not button13.is_pressed:
        stepper1 = stepper.FORWARD
    else:
        stepper1 = None

    if keyboard.is_pressed('r') and not button27.is_pressed:
        stepper2 = stepper.BACKWARD

    elif keyboard.is_pressed('l') and not button5.is_pressed:
        stepper2 = stepper.FORWARD
    else:
        stepper2 = None


    if stepper1:
       kit1.stepper1.onestep(stepper1, style=stepper.DOUBLE)

    if stepper2:
       kit1.stepper2.onestep(stepper2, style=stepper.DOUBLE)
I'm not sure if I have the stepper/key/button mapping correct. It would be a lot easier to keep things straight if you added a little structure to the code. In this example I use a DOF class to to keep the pertinent information for a stepper motor organized.
class DOF():
    """A single degree of freedom.
    stepper - The stepper motor I control
    forward - Function returns True if forward motion is requested
    backward - Function returns True if backward motion is requested
    fwd_limit - Function returns True if forward limit is reached
    bwd_limit - Function returns True if backward limit is reached
    """
    def __init__(self, stepper, forward, backward, fwd_limit=None, bwd_limit=None):
        self.stepper = stepper
        self.fowrard = forward
        self.backward = backward
        self.forward_limit = fwd_limit
        self.backward_limit = bwd_limit

    def move(self):
        """Move the stepper if move is requested and not prevented by limits"""
        if self.forward():
            if self.forward_limit is None or not self.forward_limit():
                self.stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)

        if self.backward():
            if self.backward_limit is None or not self.backward_limit():
                self.stepper.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

arm = DOF(
    stepper=kit.stepper1,
    forward=lambda:keyboard.is_pressed('f'),
    backward=lambda:keyboard.is_pressed('b'),
    fwd_limit=lambda:Button(12).is_pressed,
    bwd_limit=lambda:Button(13).is_pressed
)

leg = DOF(
    stepper=kit.stepper1,
    forward=lambda:keyboard.is_pressed('l'),
    backward=lambda:keyboard.is_pressed('r'),
    fwd_limit=lambda:Button(27).is_pressed,
    bwd_limit=lambda:Button(5).is_pressed
)

while True:
    arm.move()
    leg.move()
Reply
#5
(Jun-13-2021, 05:31 AM)bowlofred Wrote: What is the 200 loop for? Why not just move the stepper as long as a button is pressed and stop when it is released?

That is to back off the arm as it reached its limit end stop. I hit f it goes all the way back activates the gpio stops, then backs off 1.5 rotations. One rotation equates to 200 steps.
Reply
#6
(Jun-13-2021, 01:50 PM)deanhystad Wrote: Only allow motion when the associated limit switch is not pressed.
stepper1 = None
stepper2 = None
while True:
    if keyboard.is_pressed('f') and not button12.is_pressed:
        stepper1 = stepper.BACKWARD

    elif keyboard.is_pressed('b') and not button13.is_pressed:
        stepper1 = stepper.FORWARD
    else:
        stepper1 = None

    if keyboard.is_pressed('r') and not button27.is_pressed:
        stepper2 = stepper.BACKWARD

    elif keyboard.is_pressed('l') and not button5.is_pressed:
        stepper2 = stepper.FORWARD
    else:
        stepper2 = None


    if stepper1:
       kit1.stepper1.onestep(stepper1, style=stepper.DOUBLE)

    if stepper2:
       kit1.stepper2.onestep(stepper2, style=stepper.DOUBLE)
I'm not sure if I have the stepper/key/button mapping correct. It would be a lot easier to keep things straight if you added a little structure to the code. In this example I use a DOF class to to keep the pertinent information for a stepper motor organized.
class DOF():
    """A single degree of freedom.
    stepper - The stepper motor I control
    forward - Function returns True if forward motion is requested
    backward - Function returns True if backward motion is requested
    fwd_limit - Function returns True if forward limit is reached
    bwd_limit - Function returns True if backward limit is reached
    """
    def __init__(self, stepper, forward, backward, fwd_limit=None, bwd_limit=None):
        self.stepper = stepper
        self.fowrard = forward
        self.backward = backward
        self.forward_limit = fwd_limit
        self.backward_limit = bwd_limit

    def move(self):
        """Move the stepper if move is requested and not prevented by limits"""
        if self.forward():
            if self.forward_limit is None or not self.forward_limit():
                self.stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)

        if self.backward():
            if self.backward_limit is None or not self.backward_limit():
                self.stepper.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

arm = DOF(
    stepper=kit.stepper1,
    forward=lambda:keyboard.is_pressed('f'),
    backward=lambda:keyboard.is_pressed('b'),
    fwd_limit=lambda:Button(12).is_pressed,
    bwd_limit=lambda:Button(13).is_pressed
)

leg = DOF(
    stepper=kit.stepper1,
    forward=lambda:keyboard.is_pressed('l'),
    backward=lambda:keyboard.is_pressed('r'),
    fwd_limit=lambda:Button(27).is_pressed,
    bwd_limit=lambda:Button(5).is_pressed
)

while True:
    arm.move()
    leg.move()

The only way to move things is to use a for I in loop. The command syntax is very specific.
https://learn.adafruit.com/adafruit-dc-a...spberry-pi
Basically you are commanding a pca9685 chip using a library interface over i2c and it only responds a certain way using the library command framework as input.

It took me a while to figure that out for multiple controls and many more to find a compatible gpio control setup that actually worked. Too much in the python arena is changing and some stuff that worked once is not working now. Plus the pi OS updates for the 4 and whatever else is coming down the pike also throws a wrench in things if I go to recreate this months or years later. Then I throw a monkey wrench as I do not have proper schooling and just read what I can get a hold of and try to stick to a syntax that works for me. Once I get it working completely I then add loads of comments for documentation.

The idea is sound though and I could do a rewrite next go around and see what I can make work. I will try to get a picture of things so you get a better picture. As the script piece is just a control interface for the hardware that I am basically fabricating and adapting to make work for my setup...
Reply
#7
I did some more playing. I integrated another piece, that works. The stepper motors I had to do some tweaking.

#!/usr/bin/python

import cwiid
import RPi.GPIO as GPIO
import sys
from time import *
import subprocess
import board
import time

#this is for stepper motor controls, keyboard initiates movement, Button is limit switches
import keyboard

#gpiozero is the only library I have found that functions with the current pi and hardware setup I am using
from gpiozero import Button

#these are part of the Blinka libraries Adafruit has.
from adafruit_motorkit import MotorKit
from adafruit_motor import stepper
kit1 = MotorKit()

# this is for stepper motors and servo board
from board import SCL, SDA
import busio
from adafruit_pca9685 import PCA9685
i2c_bus = busio.I2C(SCL, SDA)
pca = PCA9685(i2c_bus)
pca.frequency = 50

# standard servo declearations for controls
from adafruit_servokit import ServoKit
kit = ServoKit(channels=16)

# this is for the new non-conflicting gyroscope
from adafruit_lsm6ds.lsm6ds33 import LSM6DS33
i2c = board.I2C()
sensor = LSM6DS33(i2c)


#12 and 13 are for one motion assembly backing up one full turn
button12 = Button(12)
button13 = Button(13)
#27 and 5 are for the other motion assembly
button27 = Button(27)
button5 = Button(5)
# while True loops endlessly.  This can be run as a service using systemd or setup as an init.d script or as an rc.local script.
while True:

#  sensor.gyro_rate=250
  gyro_x, gyro_y, gyro_z=sensor.gyro
#  rightxa=(((int(gyro_x--256)/(256--256))*180))
  rightxa=(((int(gyro_x--5)/(5--5))*180))
#  rightya=(((int(gyro_y--256)/(256--256))*180))
  rightya=(((int(gyro_y--5)/(5--5))*180))
#  rightza=(((int(gyro_z--256)/(256--256))*180))
  rightza=(((int(gyro_z--5)/(5--5))*180))
  rightx = round(rightxa)
  righty = round(rightya)
  rightz = round(rightza)
  kit.servo[5].angle=rightx
  kit.servo[14].angle=righty
  kit.servo[7].angle=rightz
  print("gx", rightx, "gy", righty, "gz", rightz)
  time.sleep(0.6)
  print("rx", gyro_x, "ry", gyro_y, "rz", gyro_z)
  print("Gyro X:%.2f, Y: %.2f, Z: %.2f degrees/s" % (sensor.gyro))


  if button12.is_pressed:
    print("button12 pressed")
    for i in range (200):
 #     kit1.stepper1.release()
      kit1.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)

  if button13.is_pressed:
    print("button13 pressed")
    for i in range (200):
  #    kit1.stepper1.release()
      kit1.stepper1.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)

  if keyboard.is_pressed('f'):
#    kit.servo[14].angle=10
 #   kit.servo[5].angle=10
  #  kit.servo[7].angle=10
    print("f is pressed")
    for i in range (3300):
      if button13.is_pressed:
        i = 3300
        break
      kit1.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)

  if keyboard.is_pressed('b'):
#    kit.servo[14].angle=170
 #   kit.servo[5].angle=170
  #  kit.servo[7].angle=170
    print("b is pressed")
    for i in range (3300):
      if button12.is_pressed:
        i = 3300
   #     kit1.stepper1.release()
        break
      kit1.stepper1.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)

# This is for channel 2 stepper motor.

  if button27.is_pressed:
    print("button12 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)
      if i == 200:
        kit1.stepper2.release()

  if button5.is_pressed:
    print("button13 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
      if i == 200:
        kit1.stepper2.release()

  if keyboard.is_pressed('r'):
    print("f is pressed")
    for i in range (3500):
      if button27.is_pressed:
        break
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
      if i == 3500:
        kit1.stepper2.release()

  if keyboard.is_pressed('l'):
    print("b is pressed")
    for i in range (3500):
      if button5.is_pressed:
        break
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)
      if i == 3500:
        kit1.stepper2.release()
Reply
#8
I ended up having to add if statements within the range statements to trigger different behaviors based upon GPIO triggering and end range behavior. The other thing I found is that I either have a bad power supply or a bad stepper motor.

break is used to stop the progression of the range. I did not see much documentation in examples of what I was trying to do so it was playing with formatting to get the desired behavior.

Stepper 2 is for a blade gauntlet and stepper1 is for the pack. They are both rigged the same way.

The addiational code in the post above is for a gyroscope as I start integrating other pieces for the prototype build out.

# This is for channel 2 stepper motor.

  if button27.is_pressed:
    print("button12 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)
      if i == 200:
        kit1.stepper2.release()

  if button5.is_pressed:
    print("button13 pressed")
    for i in range (200):
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
      if i == 200:
        kit1.stepper2.release()

  if keyboard.is_pressed('r'):
    print("f is pressed")
    for i in range (3500):
      if button27.is_pressed:
        break
      kit1.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
      if i == 3500:
        kit1.stepper2.release()

  if keyboard.is_pressed('l'):
    print("b is pressed")
    for i in range (3500):
      if button5.is_pressed:
        break
      kit1.stepper2.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)
      if i == 3500:
        kit1.stepper2.release()
This pasted code piece is a functioning chunk for a limit travel assembly, but the triggering works.

I did find that a couple of the switches were wired to be triggered open instead of closed.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  function return boolean based on GPIO pin reading caslor 2 1,170 Feb-04-2023, 12:30 PM
Last Post: caslor
  class Update input (Gpio pin raspberry pi) caslor 2 788 Jan-30-2023, 08:05 PM
Last Post: caslor
  Webhook, post_data, GPIO partial changes DigitalID 2 983 Nov-10-2022, 09:50 PM
Last Post: deanhystad
  How would I use Watchdog to get triggered when DVD is inserted? Daring_T 12 4,714 Aug-17-2021, 01:49 PM
Last Post: Daring_T
  Seemingly unstable GPIO output while executing from RetroPie LouF 6 3,919 Feb-19-2021, 06:29 AM
Last Post: LouF
  Process halting JarredAwesome 0 1,529 Dec-24-2020, 11:46 PM
Last Post: JarredAwesome
  Picture changing triggered by GPIO q_nerk 2 2,571 Dec-14-2020, 03:32 PM
Last Post: DeaD_EyE
  GPIO high if network IP has good ping duckredbeard 3 2,330 Oct-12-2020, 10:41 PM
Last Post: bowlofred
  raspberry pi tank gpio help jatgm1 1 2,401 May-06-2020, 09:00 PM
Last Post: Larz60+
  How do you take terminal inputs w/o halting running code? Bhoot 3 2,581 Apr-17-2020, 08:31 AM
Last Post: deanhystad

Forum Jump:

User Panel Messages

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