I have a class for a DC-motor. It has attributes that can e.g. change the set rotational speed. In order to control the actual speed I would like to run a thread that guards the acceleration. So if a user sets a new speed the thread will slowly increase the actual speed to match the set speed. My approach:
import time
import threading
import RPi.GPIO as GPIO
class motorController:
#constructors
def __init__(self,maxPower,powerPin,directionPin,direction=True):
self.maxPower = abs(maxPower)
self.power = 0 #initially off
self.setPower = 0
#set pins motors are connected to
self.powerPin = powerPin
self.directionPin = directionPin
self.direction = direction
#initialize PWM
GPIO.setmode(GPIO.BCM)
#initialize powerPin
GPIO.setup(self.powerPin, GPIO.OUT) # set pin to output
self.powerPwm = GPIO.PWM(self.powerPin, 100) # Initialize PWM on pwmPin 100Hz frequency, max is 8kHz, min is 10Hz
self.powerPwm.start(self.power) # Start PWM with 0% duty cycle
#initialize directionPin
GPIO.setup(self.directionPin, GPIO.OUT,initial=self.direction) # set pin to output
#initialize controll deamon
self.__lastCall = time.time()
self.setPointIsNotReached = threading.Condition() #currently unused
self.deamonTimeLock = threading.Lock()
self.controllThread = threading.Thread(target=self.__powerControllerDeamon())
self.controllThread.setDaemon(True)
self.controllThread.start()
def setTargetPower(self,setPower):
setPower = min(setPower,self.maxPower)
self.setPower = max(setPower,-self.maxPower)
with self.deamonTimeLock:
self.__lastDeamonCall = t
def __setPower(self,power):
#limit power to maxPower
self.power = min(abs(power),self.maxPower)
self.powerPwm.ChangeDutyCycle(self.power)
#set rotation direction
if power < 0:
self.direction = False
else:
self.direction = True
GPIO.output(self.directionPin, self.direction) #set to 3.3V if direction is true, or 0V if direction is false
def __powerControllerDeamon(self):
#private method that controls the power of the motor
t = time.time()
dt = t-self.__lastCall
if self.power > self.setPower:
m = -50 #ramp from 100 to 0 in minimal 2 sec
else:
m = 20 # ramp from 0 to 100 in minimal 5sec
newPower = self.power + m * dt
#detect if power is reched through change of sign
dP = self.setPower - self.power
dP2 = self.setPower - newPower
if dP*dP2 <= 0: #change of sign or one is zero
newPower = self.setPower #set point reached
else:
with self.setPointIsNotReached
self.setPointIsNotReached.notify()#set point NOT reached
print(newPower)
self.__setPower(newPower)
with self.deamonTimeLock:
self.__lastDeamonCall = t
and
from motorController import motorController as mC
import time
try:
m1 = mC(100,18,17)
m1.setTargetPower(100)
time.sleep(10) #should have powered up by now
except BaseException as e:
import RPi.GPIO as GPIO
GPIO.cleanup()
raise(e)
In this example, the thread function is called once and then never again.
I'm new to threading and python. My questions:
Your __powerControllerDeamon
method should contain a loop that runs until it reaches the desired speed or until it is told to stop.
Since it doesn't contain a loop, it will run once and exit.
Note that this loop should also contain a small amount of sleep
, to prevent it from hogging the CPU.