Page 1 of 1

Multithreading / Multiprocessing with Python on a Raspberry PI with connected motors

Posted: Thu Jan 16, 2020 9:12 am
by FunnyAstronaut
I am new in this community and also in programming. I have some basic knowledge in Arduino programming and also in Python (nothing special, just blinky LEDs and so on).

So I am now on a rather big project. I know it might be a tough one to start with. The basic plan is to connect 6 stepper motors with 6 rotary encoders to a Raspberry PI. To get the needed I/Os I am using some I2C port extenders. The stepper controllers are postep25 at the moment.

I now have my basic setup for testing with two steppers and two encoders. When I use a stepper or encoder by its own in a Python programm everything works well. As soon as I combine everything into one programm the motors slow down. In my understanding python just works through the code from top to bottom. So I can understand why the speed of my steppers slows down. Is there any way to avoid this? I have already read about mulithreading and tried to use it, but it didn't change anything. Would multiprocessing be a solution?

Any help or hints would be much appreciated =)


Code: Select all

#importiere Libraries

from threading import Thread
import threading
import time
from time import sleep
import RPi.GPIO as GPIO
import smbus
import sys

#PinOut

Ro1APin = 14                                        # Encoder 1 Pin A
Ro1BPin = 4                                         # Encoder 1 Pin B

Ro2APin = 18                                        # Encoder 2 Pin A
Ro2BPin = 17                                        # Encoder 2 Pin B

b = smbus.SMBus(1)                                  # Bus Aktiv

#Variablen festlegen

globalCounter1 = 0
flag1 = 0
Last_RoB1_Status = 0
Current_RoB1_Status = 0

globalCounter2 = 0
flag2 = 0
Last_RoB2_Status = 0
Current_RoB2_Status = 0

#GPIO Setup

def setup():

        b.write_byte_data(0x21,0x00,0x00)                   # I2C Device 21 alle IOS aktiv schalten (Motor 1)
        b.write_byte_data(0x20,0x00,0x00)                   # I2C Device 20 alle IOS aktiv schalten (Motor 2)

        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(Ro1APin, GPIO.IN)
        GPIO.setup(Ro1BPin, GPIO.IN)
        GPIO.setup(Ro2APin, GPIO.IN)
        GPIO.setup(Ro2BPin, GPIO.IN)

#Klasse Motor1 Rotation

class M1Rotation:

    def __init__(self):
        self._running = True

    def terminate(self):
        self._running = False

    def run(self):
        while True:
            b.write_byte_data(0x21,0x14,0x01)       # I2C Device 21, Bank A, Bit 0 High => Motor Stp
            sleep(0.005)
            b.write_byte_data(0x21,0x14,0x00)       # I2C Device 21, Bank A, Alle Bits 0


#Klasse Motor2 Rotation

class M2Rotation:

    def __init__(self):
        self._running = True

    def terminate(self):
        self._running = False

    def run(self):
        while True:
            b.write_byte_data(0x20,0x14,0x01)       # I2C Device 20, Bank A, Bit 0 High => Motor Stp
            sleep(0.005)
            b.write_byte_data(0x20,0x14,0x00)       # I2C Device 20, Bank A, Alle Bits 0


#Funktion Encoder1 Auslesen

def rotaryDeal1():
    global flag1
    global Last_RoB1_Status
    global Current_RoB1_Status
    global globalCounter1

    Last_RoB1_Status = GPIO.input(Ro1BPin)
    while(not GPIO.input(Ro1APin)):
        Current_RoB1_Status = GPIO.input(Ro1BPin)
        flag1 = 1
    if flag1 == 1:
        flag1 = 0
        if(Last_RoB1_Status == 1) and (Current_RoB1_Status == 0):
            globalCounter1 = globalCounter1  + 1
            return globalCounter1
            sleep(1)
        if(Last_RoB1_Status == 0) and (Current_RoB1_Status == 1):
            globalCounter1 = globalCounter1 -1
            return globalCounter1
            sleep(1)


#Funktion Encoder2 Auslesen

def rotaryDeal2():
    global flag2
    global Last_RoB2_Status
    global Current_RoB2_Status
    global globalCounter2

    Last_RoB2_Status = GPIO.input(Ro2BPin)
    while(not GPIO.input(Ro2APin)):
        Current_RoB2_Status = GPIO.input(Ro2BPin)
        flag2 = 1
    if flag2 == 1:
        flag2 = 0
        if(Last_RoB2_Status == 1) and (Current_RoB2_Status == 0):
            globalCounter2 = globalCounter2  + 1
            return(globalCounter2)
            sleep(1)
        if(Last_RoB2_Status == 0) and (Current_RoB2_Status == 1):
            globalCounter2 = globalCounter2 -1
            return(globalCounter2)
            sleep(1)


#Klasse Encoder1 Auslesen

class ReadEncoder1:

    def __init__(self):
        self._running = True

    def terminate(self):
        self._running = False

    def run(self):
        global globalCounter1
        while self._running:
            rotaryDeal1()


#Klasse Encoder2 Auslesen

class ReadEncoder2:

    def __init__(self):
        self._running = True

    def terminate(self):
        self._running = False

    def run(self):
        global globalCounter2
        while self._running:
            rotaryDeal2()


#Funktion zum Beenden

def destroy():
        GPIO.cleanup()

#Funktion Motor Threads starten

def MotorStart():
        M1Rot = M1Rotation()
        M1RotThread = Thread(target=M1Rot.run)
        M1RotThread.start()
        #M1RotThread.join()

        M2Rot = M2Rotation()
        M2RotThread = Thread(target=M2Rot.run)
        M2RotThread.start()
        #M2RotThread.join()

#Funktion Encoder Threads starten

def EncStart():
        Enc1Rd = ReadEncoder1()
        Enc1RdThread = Thread(target=Enc1Rd.run)
        Enc1RdThread.start()
        #Enc1RdThread.join()

        Enc2Rd = ReadEncoder2()
        Enc2RdThread = Thread(target=Enc2Rd.run)
        Enc2RdThread.start()
        #Enc2RdThread.join()


#Programm Start

if __name__ == '__main__':
    setup()
    MotorStart()
    EncStart()
    print(threading.enumerate())

    while True:

        print('A', globalCounter1)
        print('B', globalCounter2)