DC motor PID speed control

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
dc motors have a wide range of applications from garage door openers to robots you can control a dc motor speed using a simple pwm motor driver however such control is imprecise and the speed will vary depending on the loading conditions for applications that require more precise speed control you can use an encoder and a microcontroller to accurately control the speed to control the voltage across the motor leads connect the motor driver to your microcontroller the pin order will vary depending on your motor driver and mcu i'm using a pololu vnh 5019 motor driver and an arduino uno next connect the motor leads to the motor driver and the motor driver to an appropriate power supply for precise speed control you also need a way to measure the position of the motor shaft here i'm connecting the magnetic encoder attached to my pololu motor for a more detailed walkthrough of these connections watch our video on dc motor position control let's get started by writing code to control the motor driver here i'm defining the pins i connected to the motor driver now i'm coding a function named setmotor that writes the pwm value and sets the direction finally i'll call the set motor function to test the setup and code when i run the code with the pwm value of 50 the motor turns relatively slowly when i increase the pwm value from 50 to 100 the speed does increase but it doesn't necessarily increase proportionally and changes in the loading conditions would also affect the actual speed for accurate speed control you need to measure the velocity i'll use a magnetic encoder for this purpose an encoder works by measuring changes to the magnetic field created by a magnet attached to the motor shaft when the motor shaft rotates the encoder outputs a and b switch between high and low logic values the switching order determines the direction there are two ways to compute the speed from the encoder readings and the method you choose will affect the accuracy of your speed control in the first method you set a fixed time interval and calculate the speed by counting how many times the encoder triggered during that time interval an r code will only count when encoder a in this illustrative example the motor speeds up and the triggers happen faster in the first interval only one trigger happens so the speed is estimated to be one count per second as the motor speeds up it reaches three counts per second as you can see this method is quite coarse and typically works better for high speeds in the second method you measure the time elapsed between triggers and then estimate the speed as one count divided by the time interval here there's 1.4 seconds between the first two triggers that implies a speed of one count per 1.4 seconds or 0.71 counts per second the next interval is shorter so the speed measurement increases to 1.53 counts per second you can see that the second method more accurately computes speed however this method introduces other issues that are not immediately obvious we'll get to that later let's test the speed measurement methods on the arduino here i'm defining the encoder pins and the global variable that stores the number of counts read by the encoder now i'll trigger an interrupt when encoder a rises each time the interrupt is triggered it will call the read encoder function inside the read encoder function i'll iterate the global variable pose i forward or backward depending on the logical value of encoder b here i'm editing the driver input to ramp the speed up over 3 seconds to safely access the posei variable we'll use an atomic block to compute the speed using the first method we need to know how much time has elapsed between each iteration of the loop function i'll measure the time elapsed using the micros function and then estimate the time interval by taking the difference between that and the last time measurement next i'll compute the difference between the current and previous encoder count taking the ratio of these two quantities estimates the speed in units of encoder counts per second let's see what the speed measurements look like you can see that the calculated speed increases as we expect but the speed bounces between levels these levels are a result of the discrete encoder measurements this is the main limitation of method one but as you'll see later in the video there are ways of alleviating this effect in the second method we'll estimate the elapsed time inside the interrupt function first i'll define global storage variables i'll call micros inside the interrupt to measure the current time the elapsed time is the difference between the current time and the previous interrupt time so the estimated speed is plus or minus 1 divided by the elapsed time safely retrieving the estimated velocity in the atomic block and writing the estimated speed to the serial port completes this part of the code let's test it you can see that this second method provides a smoother estimate for the speed however it can cause other issues later on but we'll get to that so far we've computed the speed using two different methods however the speed is measured in units of encoder counts per second for most practical applications you'll want to use standard units like rotations per minute here i'll convert the speed to rotations per minute using my motor's specifications this polar low motor records a maximum of 64 counts per motor shaft rotation we're only measuring one out of every four events so we measure 16 counts per rotation of the motor shaft this motor has a gearbox with an 18.75 to 1 gear ratio i've also added external years with a 2 1 gear ratio all of this together means there are 600 encoder counts per rotation of the arrow to convert the speed in the code i'll divide the measured speed by 600 to convert the counts to rotations of the arrow then i'll multiply by 60 to convert seconds to minutes the result is the speed and rpms when i run the code the velocity is now measured in rpms the speed computed by method 1 appears coarse due to the discrete encoder steps as the speed changes there are high frequency oscillations between discrete levels another way to think about this is in the frequency domain here i've computed the power spectrum frequencies below 30 hertz contain useful measurements you can see that there's also a substantial amount of high frequency content this is primarily due to the measurement switching between discrete levels as the speed increases applying a low-pass filter will remove these high frequencies and yield an improved estimate of the speed this will be important for our speed control designing a low-pass filter requires that you specify a cut-off frequency frequencies above the cutoff are attenuated while those below are preserved i'll use a cutoff of 25 hertz creating the discrete implementation of the filter requires that you use a library or do some ugly math i made another video that teaches you the details so if you want to create your own filter check it out using the method i showed in that video i created this discrete update equation for the 25 hertz low pass filter let's see if the filter works here i'm plotting the raw and filtered signals together you can see that the high frequency oscillations are substantially reduced in the power spectrum you can see that the low frequencies are largely unaffected the high frequency content has been attenuated but not completely removed let's implement the filter on the arduino first i'll define global variables for the raw and filtered speed now i'll compute the filtered speed using the update equation i'm also storing the raw speed for use in the next iteration to complete the code i'll set a delay of one millisecond to maintain a consistent sampling frequency let's ramp the speed again to test our newly implemented filter you can see that the filter has smoothed the jumps present in method one we'll use this filtered speed in our control loop now that we've tested the motor velocity measurements we're ready to use a feedback loop to precisely control the speed pid control is an easy to implement all-purpose method that works to control a variety of systems there are three terms in pid control proportional integral and derivative that's what pid stands for for speed control we'll start with a proportional controller to reduce a steady state error we'll add an integral term and we'll drop the derivative term altogether so really we'll use a pi controller a proportional controller works by adjusting the voltage across the motor leads to bring the current speed closer to a target speed called the setpoint we'll start building our feedback controller by computing the difference between the setpoint and the current speed the result is the error commonly denoted e consider the case where the current speed is below the setpoint the error is positive in this example the error is 24 rpms on the other hand if the current speed is above the setpoint the error is negative in the first case the error is positive and we want to apply a positive voltage to speed the motor up in the second case the error is negative and we want to apply a negative voltage to slow the motor down proportional control takes advantage of this correspondence by directly using the error to define how much voltage to apply to the motor leads the error is multiplied by a constant kp so we can increase or decrease the magnitude of the response in this example i set kp equal to 0.5 this means the control signal u will provide 12 volts to speed up the motor in the first case in the second case negative 6 volts will be applied slowing the motor down we can summarize the proportional controller using a block diagram for velocity control the controlled object known as the plant is the motor and motor driver the output of the motor is the current speed v the target speed is vt the difference between vt and v produces the error e the proportional controller simply multiplies e by the gain kp to generate the control signal u the value of u determines the magnitude and sign of the voltage applied to the motor let's implement the proportional controller on the arduino first define a target speed define kp and set it to 1 for now we'll adjust it later compute the error as the difference between the target and filtered velocity the control signal u is simply the error multiplied by kp we can compute the direction that the motor spins as a sine of u we can't actually specify the voltage across the motor leads directly instead we'll specify the pwm value applied to the motor driver as the magnitude of the control signal u cap the pwm signal at 255. we're ready to test the p controller with this value of kp the motor responds a little slowly and is about 30 rpms below the 100 rpm target this indicates that not enough voltage is being applied to the motor so the gain kp is too small let's increase kp to 20 and see how the system responds uh-oh looks like i may have overdone it you can see that while the target is reached quickly it is overshot and then the motor jitters around the target the voltage being applied is too large and the electromechanical properties of the motor cause it to enter a cycle of overshooting and undershooting there's over an amp of current being wasted as the proportional controller fights with itself let's reduce kp to 3 to remove the jitter that's better the controller is now able to switch between the speeds without becoming unstable however we're still not hitting the target let's modify the controller to improve this adding an integral term to the controller will reduce the steady state error the integral term requires that you take the integral of the error and then multiply it by a gain ki then you sum the proportional and integral terms to obtain the control signal u you can use the first order finite difference estimate shown here to compute the integral let's implement the integral term on the arduino define a global variable for the integral next define k i the integral term coefficient update the integral inside the loop function using the difference equation to complete the pi controller add the integral term into the expression for the control signal u when i run the pi controller it's kind of working the steady state error has been reduced but now there's an issue when we switch the setpoint to zero rpms it's not actually reached this looks bad but let's increase kp to 5 and ki to 10 to give our controller a bit more power now the response is looking better the controller is able to reach zero speed and the target speed of 100 rpms while making this video i encountered several issues with my speed controller let me walk you through a few different configurations i tried and why they didn't end up working out i thought the second method for computing the velocity would be better however when the motor stops the interrupt stops triggering this means you can never measure zero velocity because the measurements happen inside the interrupt this aggravates the problem of setting the speed to zero rpms you can see the large oscillations here what about doubling the control parameters to ensure a fast response you can and the response is still stable but it hurts more than it helps causing additional overshoot and a little jitter you're also probably wondering curio res why did you waste our time with that low-pass filter was that really necessary if we turn the filter off some of the response is okay but there's jitter especially when i target a low speed like 10 rpms i know it's hard to see from the graph but just listen to this jitter [Music] let's turn the filter back on ah much better you
Info
Channel: Curio Res
Views: 111,133
Rating: undefined out of 5
Keywords:
Id: HRaZLCBFVDE
Channel Id: undefined
Length: 15min 28sec (928 seconds)
Published: Mon Sep 13 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.