Executing two blocks of servo code at the same time

Hey guys, I have the following two blocks of code, controlling servos, that I wanted executed at the same time, not one after the other, any ideas how to go about this?

                kit.servo[7].angle = 90
                kit.servo[15].angle = 45
                time.sleep(0.25)
                kit.servo[15].angle = 0
                time.sleep(0.2)
                kit.servo[7].angle = 0
                time.sleep(1)
                
                kit.servo[3].angle = 90
                time.sleep(0.25)
                kit.servo[3].angle = 0
                kit.servo[11].angle = 0
                time.sleep(0.2)
                kit.servo[11].angle = 45
                time.sleep(1)

Thanks,
-FF

I have just tried using threading, which executes the block together, but if they’re in a while True loop, it comes back after one iteration and says threads can only be started once. Any ideas?

#Libraries
import RPi.GPIO as GPIO
import time
import threading
from adafruit_servokit import ServoKit
 
#GPIO Mode (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
 
#set GPIO Pins
GPIO_TRIGGER = 18
GPIO_ECHO = 24
 
#set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

kit = ServoKit(channels=16)
 
def distance():
    # set Trigger to HIGH
    GPIO.output(GPIO_TRIGGER, True)
 
    # set Trigger after 0.01ms to LOW
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
 
    StartTime = time.time()
    StopTime = time.time()
 
    # save StartTime
    while GPIO.input(GPIO_ECHO) == 0:
        StartTime = time.time()
 
    # save time of arrival
    while GPIO.input(GPIO_ECHO) == 1:
        StopTime = time.time()
 
    # time difference between start and arrival
    TimeElapsed = StopTime - StartTime
    # multiply with the sonic speed (34300 cm/s)
    # and divide by 2, because there and back
    distance = (TimeElapsed * 34300) / 2
 
    return distance
 
def fr():
    kit.servo[7].angle = 90
    kit.servo[15].angle = 45
    time.sleep(0.25)
    kit.servo[15].angle = 0
    time.sleep(0.2)
    kit.servo[7].angle = 0
    time.sleep(1)
    
def fl():
    kit.servo[3].angle = 90 
    time.sleep(0.25)
    kit.servo[3].angle = 0
    kit.servo[11].angle = 0
    time.sleep(0.2)
    kit.servo[11].angle = 45
    time.sleep(1)
    
Thread1 = threading.Thread(target=fr)
Thread2 = threading.Thread(target=fl)

if __name__ == '__main__':
    try:
        while True:
            dist = distance()
            if dist >= 10:
                print ("Walk = %.1f cm" % dist)
                Thread1.start()
                Thread2.start()
                Thread1.join()
                Thread2.join()
                
            else:
                print ("Stop = %.1f cm" % dist)
                time.sleep(3)

Thanks,
-FF

Hi FF
Not too sure how Python works but I assume you have 2 blocks of 2 servos each block.
Also assume that it is OK to have the servos in each block to move in turn and you want to have the 2 blocks functioning at the same time.
I don’t know how good the actual multitasking is but the Pi Pico has dual core but from what I have read so far you seem to have tried this (i think that is what threading is all about). I will soon be diving into this further for another idea I have.
The only other way I can think of is have 2 micro devices.
Cheers Bob

Just figured it out, If I move the thread variable creation/assignments:

Thread1 = threading.Thread(target=fr)
Thread2 = threading.Thread(target=fl)

into the while True loop, it loops.

Heres the working code if anyone’s interested:

#Libraries
import RPi.GPIO as GPIO
import time
import threading
from adafruit_servokit import ServoKit
 
#GPIO Mode (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
 
#set GPIO Pins
GPIO_TRIGGER = 18
GPIO_ECHO = 24
 
#set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

kit = ServoKit(channels=16)
 
def distance():
    # set Trigger to HIGH
    GPIO.output(GPIO_TRIGGER, True)
 
    # set Trigger after 0.01ms to LOW
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
 
    StartTime = time.time()
    StopTime = time.time()
 
    # save StartTime
    while GPIO.input(GPIO_ECHO) == 0:
        StartTime = time.time()
 
    # save time of arrival
    while GPIO.input(GPIO_ECHO) == 1:
        StopTime = time.time()
 
    # time difference between start and arrival
    TimeElapsed = StopTime - StartTime
    # multiply with the sonic speed (34300 cm/s)
    # and divide by 2, because there and back
    distance = (TimeElapsed * 34300) / 2
 
    return distance
 
def fr():
    kit.servo[7].angle = 90
    kit.servo[15].angle = 45
    time.sleep(0.25)
    kit.servo[15].angle = 0
    time.sleep(0.2)
    kit.servo[7].angle = 0
    time.sleep(1)
    
def fl():
    kit.servo[3].angle = 90 
    time.sleep(0.25)
    kit.servo[3].angle = 0
    kit.servo[11].angle = 0
    time.sleep(0.2)
    kit.servo[11].angle = 45
    time.sleep(1)
    


if __name__ == '__main__':
    try:
        while True:
            dist = distance()
            if dist >= 10:
                print ("Walk = %.1f cm" % dist)
                Thread1 = threading.Thread(target=fr)
                Thread2 = threading.Thread(target=fl)
                Thread1.start()
                Thread2.start()
                Thread1.join()
                Thread2.join()
                
            else:
                print ("Stop = %.1f cm" % dist)
                time.sleep(3)
 
        # Reset by pressing CTRL + C
    except KeyboardInterrupt:
        print("Measurement stopped by User")
        GPIO.cleanup()

Thanks,
-FF

1 Like

Are you saying that (for instance) servo 15 does not start to move until servo 7 has rotated to 90, but you want servo 7 and servo 15 to start together? As far as I can tell for that library they should be starting at the same time (or as nearly as you can detect).

Or are you saying that (for instance) servo 7 and servo 15 should start at the same time and each should get to their final position at the same time (as in a hip and knee joint, for one step)? In that case you need to adjust the PWM rate to be inversely proportional to the distance to move (15 should have twice the PWM rate of 7)

1 Like

@Jeff, Im making a quadruped walking robot. def fr() is one legs step and def fl() is another legs step (just getting two legs working for the moment). They were running one after the other, not together. I sorted it out though by putting the thread variable creation/assignment in the while True loop, see my previous post before yours. Thanks for the reply though, that info will help me down the track!

1 Like