Transcripts
1. Promo Video: How much do you need to turn the front wheel of a car to make it follow a trajectory or move the elevator for plane to achieve the required bit Django, or applied power, two propellers to fly a drone. For movies ship as you want, or even regulate current in an electric motor to control a robotic arm. All of them are systems. And the might be different, but they can all be mathematically modeled and control using the same fundamental logic. My name is Mark. I'm an Aerospace and robotics engineer and I want to teach you how to do it. After this course, you will know how to model a system using state-space equations, then how to apply a PID and the model predictive controller, or Mpc to it, will first use PID to control a simple magnetic train that needs to catch objects that randomly fall from the sky. Then we'll use MVC to achieve a simple link changing maneuver with a car on a straight road. For each system, there is a stimulation in Python to create a bridge between intuition, mathematics, encoding, three skills that every engineer needs to have. The coast will be available for you to download and experiment with. And I will explain to you the MPC code in a special section. When I teach the My goal is to make you understand it. Fundamentally, if you memorize stuff, then you will forget it quickly. But if you understand it, it will stay with you for good. Only then you will be able to modify and apply this knowledge to other systems. I'll make sure that you will truly mastered the content before you by taking a look at some of my free videos. And if you like what you see enrolling in the course, and let's get started. Looking forward to seeing you there.
2. Intro to Control - how to control systems with a controller 1: welcome in this section, I will teach you something really, really practical. I'm going to teach you how to design a proportional and the proportional, derivative and integral controller otherwise known as a P I. D controller. And I'm gonna do it from a calculus point of view. So let's get started. First of all, what is a controller? I'm going to use a water tank example to explain to you. So let's imagine that we have a water tank here that can contain a maximum off 100 cubic meters of water inside it. However, right now, at this moment, you only have 50 cubic meters of water. So the blue one is water and it's their reality. It's how much water there is now. And now we're going to put a red line here, and we're going to call it a reference line. So it's like a target. It's how much water you want. So the blue one is how much water you have right now, and the red one is how much you want to have. It's a reference line, and now you can calculate an error, which is reference miners, Will you, in other words, how much water You want miners? How much you have right now and right now it's equal. Right? So you want 50 cubic meters of water and you have 50 kilometers of water, so your error is zero cubic meters. However, now, at this moment you have 50 cubic meters of water. But you only want 20 cubic meters of water. So this is your new target. This is your new reference line. So this is how much you want now. But you have 50 cubic meters of water. You calculate the error, which is reference miners current volume and your error is negative. It's minus 30 kilometers. So what needs to happen now? Water needs to get sucked out of the tank. You need to get rid of some off the water in order to meet your target off 20 cube meters. So what happens now is that this water tank has a sensor and this sensor measures the volume of water every 0.2 seconds or at 50 hertz. Now you can get this frequency by dividing one by 0.2 seconds. In other words, what that means is that the sensor measures the volume of water 50 times a second. So in one second it takes 50 samples off the level of water. And so what happens next is that the pump starts taking water out of the tank. So the amount of water in the tank decreases and decreases and decreases until it reaches the target. The reference line. And now the amount of water that you have equals how much you want to have. So you're error Term is zero q meters. Now, for some reason now you want to have 80 cubic meters of water in your tank, but you only have 20 kilometers. So if you calculate the error, you have a positive 60 kilometer error. Now, again, you have the sensor that measures the volume of water at 50 hertz and now the pump starts pumping border inside the tank. And so the level off water increases and increases and increases until his reaches 80 kilometers. And no, you have 80 cubic meters off water and you want to have 80 cubic meters of water. So you're error term is zero kilometers. Now, if we start generalizing it, if we think about our water tank, what is it exactly Well, it's a system. We can say that our water tank is a system and you can have all kinds of systems. An airplane can be a system. A rocket can be a system. Some kind of heating device can be a system. So whatever you can imagine or whatever you're working with can be a system. So right now we're working with a water tank. So we say that our water tank is our system and that system has an output and it has an input. So what is exactly an output? An output of the system is something that we can observe something that we can measure, and it has to be relevant. So let's say we could also measure how many molecules off water we have in the water tank, right? But we wouldn't do that because it's not relevant for our situation. For us, they're relevant values divorce you. It's how many cubic meters of water we have in the tank, not how many molecules of water we have in the tank. So an output is something that we can observe. Something that we measure typically with sensors and the input into our system is a mass flow rate. It's unit is kilograms per second. So it's how many kilograms of water flows into our tank per second. And if we think about the input than the in place some kind of action that causes output to change. So let's say if we increase our input, if we increase our mass flow rate, we have more kilograms of border flowing into our tank per second, then that influences our output. Right Then our volume increases. And if this mass flow rate is negative, if it's not positive, if it's negative, if it's a negative value, if it's let's say, minus 50 kilograms per second, then it causes volume to decrease right, So the input, depending on what we put here, it influences our output. So a positive mass flow rate would increase the volume off water and negative mass flow rate would decrease. It
3. Intro to Control - how to control systems with a controller 2: And now let's see where controller fits in in all of this. This is our system. This is a water tank system, right? And it has an input which is a mass flow rate. How many kilograms of water per second flows into the tank and then on the other side, we're measuring the output with a sensor. We're measuring the volume of water, a relevant output. So remember, we're only interested in relevant outputs relevant measurements. So now we need to decide how to best influence our input. In our case, our mass flow rate in orderto achieve our desired output. And the controller is nothing but a brain, a brain that decides how to best influence our system input in order to achieve our desired output. So, for example, if we want to achieve our desired output very fast, then the controller might decide that. Okay, let's put a lot of mass for rate in here, or if you want to achieve the desired volume in a slow way, then the controller would say that. Okay, let's not put so much mass low rate in here. Let's just put a little bit so that the level of water would increase, but slowly So the way it works is that this is your output volume, right? And your volume goes here and here. This is your reference like, this is the red line, right? This is how much volume of water you want and this is how much you have. And so here you have a plus sign here and you have a negative sign here. So reference miners volume will give you an error So a controller will take in an error term, which is reference minds volume It will take in the error term. And so for the controller, the input is the error term and then the output for the controller the controller output would be actually the system input. It would be the mass floor rate and also the system input. Since it's controlled input by the controller right then we also call it ah controlled input or control action. So the controller decides how to best influence the mass flow rate in orderto achieve your desired volume. And he does so by trying to drive the air Attar 20 So you want the error to become zero Because then your reference equals your volume, and a very simple controller would look something like this in a mathematical way. Let's say if your error is less than zero, then let your mass flow rate B minus 10 kilograms per second, right? It makes sense that if your error is negative, then that means that your reference is less than your volume. So you want your water to go down so your mass flow rate should be negative. Then that means that water gets out of the tank and the amount of water in the tank decreases. If you're error zero, then the controller says, apply zero kilograms per second, and here error is bigger than zero. Then apply 10 kilograms per second. So now you want the level of water in the tank to increase, so you apply a positive mass low rate. And so this is a mathematical form for it. It's a piece Feist defined function, However, in a code, it could be like an if statement. If the air is less dense. Zero then let mass flow rate B minus 10 kilograms per second. LCF If error is bigger than zero, the mass flow rate equals 10 kilograms per second. Ailes and mass flow rate equals zero kilograms per second. So that could be a case when you want the level of water in the water tank to increase or decrease slowly. But if you want it to happen faster than the controller could be something like this. Same logic. But instead of 10 kilograms per second, you would have 100 kilograms per second here. Miners 100 here in 100 here. So in a way, nowadays, controller mostly is a computer algorithm. It's some kind of algorithm that decides based on the error that it gets, it decides how to best manipulate the controlled input, the control system, eat put to achieve a certain behavior off your output. Right. But does it always have to be a computer algorithm? Well, no, you could be a controller. You could be sitting somewhere and you could be looking at this water tank and your eyes could be like a sensor. And then your eyes look at how much water you have in the tank. You know, in your brain how much you want in your brain. You calculate the error term, and then you are the one who turns the pump on or off with your hands, which are your actuators, so you could be a controller as well. However, nowadays, in most more than systems, a controller is a computer algorithm, so you can think of it as a brain. It's a computer algorithm designed so that you could achieve your desired output by tweaking and playing around with the system input.
4. Open VS Closed Loop System: and finally, I want to explain to you the difference between an open loop system and a closed loop system. So what's the difference? The difference is that when you have an open loop system, then you only have this part right. You have your system, and then you have your input and you have your output. But in an open loop system, you don't have controllers. You don't have any feedback. So, in other words, there is no sensor that will take the measurement off the volume and then compare it with a reference and then a controller. That takes the error in to decide how to tweak the input in order to influence the output. So all that doesn't exist in an open loop system. It'll exists in a closed loop system. So a closed loop system is what we have been discussing so far. It's everything. It's everything that you can see here. But an open loop system just has a system and some kind of input and some kind of output. And now it's very important to understand that in an open loop system, since there is no controller that controls the input, the changes, Dean put based on the output, since there is no controller than in an open loop system. The system input is preplant. Before you turn your system on. In this case of pump before you turn your pump on, you preplanned the behavior off your input, the behavior off your mass floor rate. So what do I mean by that? I mean that if I turn my system on, then I say that as a function of time, my input will behave like I intended to. So this is a time axis here, and this is a mass flow rate. So this mass flow rate, it's this input here and here. It's constant as a function of time. So let's say it's always 10 kilograms per second, right? It never changes. And if it's an open loop system, if it's on lee this part, then since there is no controller, then this entire thing it's preplant. Okay, so it will always be 10 kilograms per second, and it will never change because it can't because it doesn't get any feedback from the output. It doesn't know whether it should change the input in order to influence the output somehow . So it's preplanned. Or you can pre plan it in such a way that as a function of time, your mass flow rate increases linearly, or it can be simply like that, so you can also have this kind of mass flow rate function. But the important thing to understand is that it's preplant and it doesn't change. So before you turn your system on you plan your system input. You say that as a function of time, it's gonna be like that. So maybe at the beginning it's gonna be 10 kilograms per second. And then let's say at five seconds it will be 15 kilograms per second, and then at 10 seconds it's gonna be 20 kilograms per second. But it's preplanned. And during the operation of the system, while the water tank is operational during that time, the system input does not change. Okay, now here this is a comparison often open loop system versus a close loop system. So in an open loop system, the input is preplanned. It never changes, but let's say in a closed loop system, since you'll get feedback from your sensor and then your controller basin. That error will change your input in an unexpected way. So in this case, in a closed loop system scenario, your mass flow rate might change in an unexpected way. Okay, so that's the difference. So, in an open loop system, you pre plan your input and it stays like that. It doesn't change. It will behave like you have planned it before. But in a closed loop system, it changes based on the need. So, for example, just as a simple example, you want to go from 50 cubic meters to 80 kilometers, right? And you think you think that you're going to achieve that by applying this kind of system input as a function of time. So you apply this kind of mass flow rate as a function of time. So first you give less mass flow rate and then you increase it, and then you think that you're going to go from 50 to 80 kilometers in your water tank. But then what happens is that there is a leak in the water tank, and you're not aware of that. You don't know that. So that means that if there is a leak than in a given time frame, you're not going to go from 50 to 80 kilometers. You're going to go maybe from 50 to 75 kilometers, right? Because there is a water leak. And because of that, some of the water gets lost. And since there is no feedback, you don't know about this. But if you have a close loop system, then the sensor will notice that. Okay, the error is bigger than expected, so the water level is not rising as fast as expected. So the controller will increase the system input. And that's why if you have something that you have not accounted for, then you need a close loop system for that. Because then the controller will make unexpected adjustments. And maybe because of the leak in the water tank, it will increase the amount of mass flow rate to compensate for the water that you lose because of that leak. All right, thank you very much. And I'll see you in the next video.
5. Controlling the water tank in a Python simulation: Okay, here I want to show you a water tank example. And here I'm employing this controller, the control that we talked about, so that your mass flow rate is minus ten kilograms per second when your error is less than 0. And when your error is bigger than 0, then your mass for radius plus ten kilograms per second. And when your error is 0, then your mass flow rate is 0 kilograms per second. And you can see that, OK, the control works. It is following the reference line, but it's too slow, right? So if you look at this timeline here, 5 thousand seconds, so that's around a little bit less than 1.5 hours. And let's say that you need this tank to fill in quickly. And then you need to empty the tank quickly as well. But the controller is not able to meet the target within the given time frame. So it is following the reference line, but it is not able to meet the required targets in the given timeframe. So let's see if we're going to implement that other controller that we talked about. So instead of minus 1010 kilograms per second, maybe if we increase our mass flow rates to minus one hundred and one hundred kilograms per second maybe then we will be fine. So let's see. So now the mass flow rates are minus one hundred and one hundred kilograms per second depending on the error. And you can see that now the controller is able to control the level of water in the water tank within the given timeframe. So that's very good. And you can see a little bit of wiggling here, right? That's because when the water level reaches the reference line, then at some point it's a little bit above the reference line, a little bit below the reference line. And that's why the controller switches the mass flowrate from negative to positive. And that's why you see this kind of wiggling behavior. But overall, now the mass flow rate is capable of achieving its targets. So what it is doing, it's very simply either pumping more water inside the tank per second or it's taking more water out of the tank per second. So that's how these two controllers work.
6. Intro to a proportional controller: Welcome back. So now what I wanna do, I want to explain to you what a proportional controller is. So you already know that a controller takes in an error term and it gives you a mass flow rate in our example. So an output for the controller is an input into your system. And your system was a water tank system. And so based on the error that the controller receives, it will give you a mass flow rate so that you will achieve your desired volume in the water tank. And you will achieve your desired volume in your water tank when your error becomes 0. Now there are many different controllers. And one of the controllers is a proportional controller. And essentially a proportional controller is again. So your error term is multiplied by a gain. And simply say that your mass flow rate equals that gain times your error. So from this, you can see that your mass flow rate, right? System input is proportional to the error. So maybe it's even better to see it in this graph. So your mass flow rate, your system input, it's proportional to the error. So the bigger your error, the bigger your system input, right, the bigger your mass flow rate. And also if your error is negative, then your mass flow rate is also negative. So your m dot is proportional to your error. So essentially this gain that we talked about, this gain is a slope, is the slope for this function. And by choosing KP, you choose the slope for this line. Now, this KP, It has the units of kilograms over seconds times m cube. And that is because the slope, the KP is nothing else but delta m dot over delta error. And if you look at their units, then you will get your units for the KP. And so when you choose your gain, then for example, if you choose a very large gain, then this function would be something like this with a big slope. That means that if the error increases or changes a little bit, then you will have great changes in your system input. However, if you give your controller a small gain, then your function would look something like this. And that means that if there's some kind of change in your error, then your mass flow rate won't change that much. So that's what you're doing. When you choose your KP, when you choose your gain for your controller, you're choosing a slope for your function, right? You're choosing how your mass flow rate is proportional to your error. Whether it's proportional in a strong way or is proportional in a weak way. So let me just show you very quickly how a proportional controller would influence your water tank. So you can see that now the response is different. It's not linear. So at the beginning, right? When the air is great and also the mass flow rate is huge. But then as you get closer and closer to your reference line, your error becomes smaller. And because your mass flow rate is proportional to your error, when you have a small error, you also have a small mass flow rate. And then when you have a huge error, then obviously you have a huge mass flow rate. So that's why you can see this kind of response. So the beginning, you have a huge slope and then you have a smaller and smaller slope.
7. Modelling the water tank 1: to design a good controller that works well in real life is important to simulate it in the computer. First, in real life, you measure, for example, with sensors the output and based on that, your control decides how to change your control input. And in our case, that input is a mass flow rate. In a simulation, however, you need to calculate the outward from your input. So since our input is a mass flow rate and our output is volume of water than you need to calculate your volume from your mass larayedh, so you need to have some kind of mathematical model that takes in your input variable mass flow rate and then you compute you're out variable volume. Now, one thing that you need to take into account always is that real life will always have a different output compared to what your models give you. Because you're malls, they will never take into account everything in the world. However, if the difference between your model and real life is small enough and you're happy with their, then you can use it. And so now what we're gonna do, we're going to create a mathematical model for our system, the water tank. And then we're going to take our proportional controller and we're going toe. Apply to our system. Toe are mathematical model off our system, and then we can simulate the entire close loop behavior.
8. Modelling the water tank 2: So now what we're gonna do We're gonna create a mathematical model for your system, which is a water tank. In order to create a mathematical system. What we need to do we need to find a mathematical model that takes your system input, a mass flow rate and from your mass flow rate and other parameters, that mathematical mall will be able to calculate your system. Output your volume in the water tank. So we need to have some kind of mathematical equation that takes in your mass for eight. And then what you get out is your volume. So how would we do that? Versatile. Let's think about what a mass will rate is. So in your water tank, you have water. So you have some kind of mass, right? You have a certain amount of border, so you have a certain amount of kilograms of water in the water tank, and your mass flow rate is just a derivative off the massive your water with respect to time, right? And that's why it's in kilograms per second. So it's D mass water with respect to time, so DT So the operator is D over DT, and then you apply it to your water mass in the water tank and you get your mass flow rate right now. Next, the mass of your border can be expressed. The volume off your water cube meters, times the density of order Kilogram per cubic meters. Right. Or using another notation. You can no Tate density as row, but the massive your water is the volume of your water times the density off your water. Now, knowing that instead of the massive fuel water you can put here volume a few of water times the density of fuel water right. And now you take this would respect the time you take that derivative off. This product will respect the time. And when you do that than the product rule, when you take the derivative will look like this. So, first of all, you take the derivative off your volume with the respect of time and you multiplied by the density of the water. And then you take the derivative off the density of your water with respect to time and you multiplied by volume. Now, since we only have water in our water tank, no other liquid than the density off your liquid inside a water tank is constant, right? And so if we take a derivative of it with respect to time, this entire term become zero because the derivative is zero. So you are only left with this part here. So a mass flow rate, assuming that we only have water, which is our only liquid, our mass flow rate is the change off volume off water with respected time times the density off water. Right, So that's your mass flow rate. Next we can rearrange the equation we can put raw on the other side of the equation. And then it would look something like this. The derivative off your volume with respect to time equals one over your water density times your mass flow rate. Right, So that's your equation. So what do we have now? We have a function where we have a time access here and then we have the derivative of the volume with respect to time here. So this is cubic meters per second, right? It's the change of volume with respect to time. It's how much volume changes in the world tank with respect to time. And so you have a function of it and dysfunction is this one? In the mathematical term, it looks like this. So what would we have to do in order to get rid of the derivative sign and just get volume as a function off Mass? Laurie? Because remember, our objective at the beginning was to get this our system output our volume as a function off our system input. Right. So not the derivative off this we respect the time, but the actual volume with respect to your system input, that's our goal. So in order to get that, we have to get rid off these days, right? So we have to take an anti derivative, which is an interval. No. One thing that I want to show you here is that you see one way how to mathematically notated when something is constant is when the derivative off that sing with respect time is zero, right? Because if, for example, dear oh, with respect to DT equals zero, that means that the density does not change. And so then you can say that the density off the liquid is constant because it's derivative equals zero, because the derivative means change. So if the derivative zero, then the quantity doesn't change. So the quantity must be constant and the mass will rate here is not constant. And sorry about this one. I cannot do anything about it. However, if you look at the mass flow rate, then, uh, the mass will rate is not constant. And mathematically it means like this. So the mass for rate would respect. Time does not equal to zero in this case than it means that the quantity is not constant. Because if it's not equal to zero, then that means that it is changing. And the master rate does change with respect to time. So it's not constant and mathematically, you would know dated like this. So when you see something like this and the directive is zero, then it's constant. And when a quantity it's derivative with respect to time is not zero, then it's not constant. But now let's ah, continue with this part now. Our master rate is a function of time by itself, right? So what we have to do? We have to take the interval off this function and then we will get rid of the derivative and then we will only have the volume of water as a function off off a mass flow rate, which is exactly what we want for our mathematical model. So the way it would look like is this Since you have DDT here, you can put this DT on the other side here, right? And then you would only be left with the volume equals one over road times and that times d t. And that's what I have done here. So the volume equals all this. And so the first thing that you see is that I put this one over row out of the integral. Why? Because it's constant, right? The mass already is not constant. It's a function of time. So that's why it has to stay inside the integral. And then I multiplies with DT However, one over Roy's constant so it can be out of the integral. And then you take them to grow on this side from zero seconds to t seconds and tease is an open variable, right? And now on the outside, you have devolved. So you have the water volume here the D water, William, A small change of four. Will you and you integrate that from the initial volume to some kind off open variable volume. So this one will be a fixed number. It's your initial condition, and then this one will be then your output variable. That will depend on time. So when you perform this integration, you will have something like this. You have volume as a function of time miners, your initial volume, all right. And that equals one over water density integral from zero to time mass for eight times DT. And then you can put the initial volume off water. It's how much water you have at the beginning. You put it on the other side, and then that's how you can express your water volume as a function of time in this four. Right now, we still have this integral form here. However, here you don't have a need to go anymore. Here. You can just say the war of volume as a function of time equals an initial volume. It's a specific number. Your initial condition, how much water you have at the beginning. Plus and then this term. Now the question now becomes, how are we gonna get rid of this? Integral. That's the question. The thing is, that if we knew how the mass flow rate depends on time. If we had a some kind of concrete function, if we knew exactly how mass flow rate changes as a function of time, then it would be easy, right, especially the function is easy. If it's a parabolic function or straight line function, it's easy now. The problem is that we don't know how this mass will rate changes with respect to time. First of all, we don't know it because we don't know how the controller is going to influence this term. This variable, this mess, Lorrie, Right? And the second thing is that sometimes you can even have functions that are so complicated that it is very hard or even impossible to integrate them analytically. And uh, in that case, and in our case when we simply don't know how mass flow rate will change. In that case, we have to do something called numerical integration. Now, what is a numerical integration
9. Numerical integration applied to the water tank model: numerical integration is essentially integrating something. But in a discreet way, integration can be seen as calculating the area under the function. Now, if you have some kind of function that is explicit in and you know the function and it is not hard to integrate, then you can just integrate it analytically. But you can also approximate the integral right. And so the way you do it, you calculate the area under the curve in an approximate way and there all kinds of different ways. You can do that and some of them are more precise. Some of them are less precise. The easiest or one of the easiest numerical integration techniques is called a trap Sawyer rule. And the way it works is that if you look at these shapes here, will do, have here you have trapped is Oh, it's right. You have a trap. Reside here. You have a trap is right here. And then you have a trap is right here. And so if you want to calculate the area off this trap is oId then what do you do? You have a zero, which is here plus a one which is here. You divided by two, and then you multiplied by delta T and delta T is this interval here, which is 0.2 seconds. All right. And then you can get the area off this trapezoid, which is approximately the area under this function curve. And then you can calculate another trap is light, Which is this one? A one plus a two divided by two times. Still the tea. Then you will know the area. This trapezoid, the same thing you can do with this trap is oy. And so when you add up, all these trap is oId areas, then what you will get. You will get this term here. All right, so this is the term that you will get when you add up. All these trap is Hoyt's and then this. Ah, initial volume. Here it's the same thing like here, these air the same terms. So when I tell you that lets integrate something analytically, it means you use those calico's rules. However, it's not always possible. I either you don't know the function or the function is very hard to integrate or even impossible to integrate, and then you have to integrate it numerically and That's actually how computers do it. So what computers do they start from time equals zero seconds, and then, after a small period of time, they calculate the area under the curve. Then, a little bit later, they calculate another area under the curve, another part and then another part. And then they add them together. That's how computers do it. And that's how engineers do it with complicated functions. Or, let's say, when they don't know the function of the mass flow rate. Because, let's say if you don't know it, if you don't know how it's gonna change, then when you at this point at time, equals 0.2 seconds, then let's say on Leah time, because 0.4 seconds, you know that the mass flow rate changed and then your function went from here to here. So when you were here a time ago, zero seconds, you didn't know that you would end up here. But when you were at time because you're opens your four seconds, then you know that you were here. And so your computer can then calculate this part and this part and add them together. So it's like looking back into the past. Okay, so that's how we would do it. We would use the numerical integration to compute this term here. And then we would add the initial volume term here. And then That's how we would get our water volume as a function of time. Now, one thing that I want to show you now is this. If you look at this term, the initial volume plus the first trap is oId. Right. Then what do you get? You will get the volume off. Water at time equals t one. So here it makes sense, right? You take your initial volume, you add the first trap is oId and then you have volume at T equals one. No, if you add another crap, is Lloyd to it? Then you will have volume at time equals t two. So this one, right? And then this entire thing here, all these foreign terms. 123 and four. If you add them all together, you will have the volume off water. Time equals t three. Right? So the other way you can write this entire thing is like this. For example, You can say that volume at T equals three equals volume. Atik was too, which is this one plus a two plus a three divided by two multiplied by Delta T. Instead of writing this, you just write volume at time because t two plus and then the last term right and you can generalize it. And in fact, it's a generalized algorithm that you can program into your computer. So if you look at it, then its volume that time Jay Wright and J can be whatever number. So it's generalized variable. It can be either one or two or three, so volume at time J equals volume at time J miners one J mines. One means that if here you have three, then here you have three miners. One equals two. So it's the same thing like here here, volume at time because three which is here, equals volume at time. Because t two, which is here, which is J miners one plus one over row times and dot at time. Jamon is one plus one row times and dot at time J divided by two multiplied by agility. So, in other words, this a two and a three It comes from here These ays right. It's this. So you have dysfunction where you take a derivative of your volume with respect to time equals one over row times mass flow rate. That means that the height off a three and a two and a one they come from here, right? And therefore, when you have a two, then this A to can be written in this way one over density times mass flow rate and dot And then said James, one you would have to and so a three would be won over density and dot a t three. All right, so Jay, in this case is three. So if you compare this equation with this one, this is a generalized version of it. So instead of three, you can have J. That means that James one equals two. And so you can put this Calgary into your coat. And then what's gonna happen is that this algorithm it will be updating itself all the time . So first of all, you will calculate volume it t one using volume it t zero and then the master rated t zero and the masquerade a t one. So using all this information, you will calculate volume at T one, then 0.2 seconds later you will calculate volume at T two using information from volume A T one at them dot t one and end up t to this Jake and go up 201,000, 10,000 depending on how many durations you have in your loop. And so here you have it again. It's just to make it clearer. So Volume a t one and t two and a t three using the information from the past from 0.2 seconds ago.
10. Combining math with the control structure: And so now this is our entire close loop system with our water tank system and our controller. And so our goal was to find a mathematical model for our water tank where we take in the macerate and we get our value and we've done it. So this is our water tank here on Lee. Now we are describing our system in a mathematical way and in fact, there two ways in mathematics how we can describe it. We can describe it using continues mathematics or discrete mathematics. And as far as computers are concerned, the computers, they, of course, operate in a discreet manner. So when you coat, then you would actually used these, uh, discreet formulas to write your code. So in a continuous way, mathematical model for your water tank looks like this volume as a function of time equals your initial volume and then one over density times the integral off the mass flow rate, which itself is a function of time, and it you multiplied by DT. Now, since you don't know in advance how this mass or it is gonna change, then we derived at discrete version of it, and this discreet version right. This is a discrete mathematical model for our system. And this one can be implemented in a computer program. For example, inside a four loop or why loop? And so this is your disagreements American Mall off your water tank. And here is your output again in rabbits, The discreet version in black. It's the continues version. It's a notation. I want to show you how you can know Tate things using continues mathematics and the screen mathematics. And so this is your output. This output goes here. You have your reference volume. It's what you want, the continues version and then the discreet version. Then you have your error return, which is here, continues and discreet. And then that goes into your controller into your proportional controller. And with that, you're gonna calculate you're new mass flow rate, so continues Version is here, and then this Chris version is here, and the way you calculate it is because it's a proportion controller, it's very easy. You just take your error turn and you multiplied by this game, KP, which is a slope off a function. Now I put here this red line just to give you like a sense off what's really happening here . What I want you to understand is that it's a continuous loop that goes around all the time . Right. So this loop it gets updated in our case at 50 hertz or every 0.2 seconds. So every 0.2 seconds, the information here gets updated. This masquerade gets updated, and then the volume off water gets updated using the information 0.2 seconds ago. So the way to look at it is like this that Okay, let's assume that on this side of this line, the variables are a little bit in the past there 0.2 seconds ago. And on this side of the line is the present. So here you have J. And here you haven't J miners one. So here you have the volume reference 0.2 seconds ago. And here is your actual volume off water inside the tank 0.2 seconds ago. All right, so all that is 0.2 seconds ago. And so you calculate the error 0.2 seconds ago. So this is a little bit in the past and then you go through the controller and now you calculate your new mass flow rate, which is macerate. Now it's what you're gonna apply to the water tank to your pump right now. So you've calculated your system input using the information from 0.2 seconds ago. So now you've calculated your new system input your new mass low rate and you feed it into your water tank system. And then you get your water volume. No. So this is now present. So it's important to know that this entire thing is a loop, and all these variables they get updated in our example every 0.2 seconds. So what you have here in 0.2 seconds, they will be here. So what you have here in 0.2 seconds time, they will become the past and they will be here. And then you will have a new value here. So that's how close Loop system works. And so that's how the control of Works controller takes in the information 0.2 seconds ago . And then it will calculate the new system input that will influence your water tank and that water tank will give you a new output, which again you will feedback into the controller. And it all happens at 50 hertz. And now I'm going to show you a couple of python simulations where we're going to test this coat and we're going to give a certain reference values for the water tank and those reference values. They're not going to be fixed. They themselves, they will be changing. And so the job of the controller is to track this reference line. So when the volume reference changes than the actual voice in the wartime needs to change as well. And so you will see it in action in the next video. Thank you very much and see you there.
11. Water tank simulation - proportional controller: So what you're seeing here is a proportional controller with a K_p value of 100. And you can see that it is going in the right direction. The volume changes in the right direction. However, the response is very slow, so it is able to track the reference line. But let's say the reference line changes faster than the volume inside the water tank. And that is because the KP value in the controller is too low. And because of that, the controller tells the pump to apply some kind of mass flow rate, but that mass flow rate is just too low. That's what the response is, not fast enough. Now the other thing that I want to show you is this, look when you're very far away from the reference line, then the volume here changes faster. And when you get closer to the reference line, then the volume changes slower because it's a proportional controller. And so when your error is less than, your mass flow rate is less. And when you mass flow rate is less, then you have less changes of volume inside the word tank. And when your mass flow rate is greater than, you have bigger changes in your tank. So you can see it here as well. So now let's change our K_p value to one hundred, ten hundred and see if it's better. So here I've applied a controller with a K_p value of 100. And now you can see that the response is much quicker because a greater KP value in the controller now tells the pump to apply greater mass flow rate magnitudes. Because of greater mass flows. Also the volume in the water tank changes faster. And so now it is able to track the reference line much better. And now we're gonna switch to another system. And it's going to be at train on magnetic rails trying to catch objects that randomly fall from the sky.
12. Intro to a PID simulation: So what you're seeing here is a train, which is this blue platform on the rails. And so these are the rails here. And we are assuming that it's a magnetic train, so it uses the magnetic forces. So essentially it little bit floats in the air due to magnetic forces. Then we don't really have to worry about friction because it's almost nonexistent. So it's easier to model our system mathematically. And the objective of that train is to catch randomly falling objects from the sky. And they are random both in height. The initial height is random, and also the horizontal position is random. And the train does not know from where those objects are going to start falling before the appear, and only after that the error between them is calculated and then the train tries to catch them. However, this train is not using the proportional controller. In fact, a proportional controller cannot be used here. If you use only a proportional controller here, then the train would not be able to catch these objects. You see a proportional controller is a very limited controller and it does not work for many systems. It worked for our water tank example. However, for many systems, it does not work. And it does not work for this magnetic train system either. So we have to use a controller that is slightly more complicated. And we're going to use a PID controller. I'm going to teach you the logic of a PID controller, a proportional integral and derivative controller. And we're first going to start with the logic of it. I'm going to explain to you exactly why a proportional controller wouldn't work here, and also how a PID controller works. And then you can also download this code in this section. So thank you very much and I'll see you in the next video where we are going to start with a PID controller.
13. PID: Modelling the train with forces 1: welcome back. So in this section I'm gonna teach you what ped controller is, and I'm gonna use it on example, which is a a magnetic train on the tracks. So this is the train, the blue block. And last time I showed you a video where that train was able to move diagonally like that. However, right now we're going to start from a simpler example. We're going to start from a case where the train can just go left and right. All right, so let's talk about the situation. What's happening here? So you have the magnetic train and like a lot objects on the planet, it has a gravitational force pulling it down wars. However, since there is no inclination since the train can Onley move left and right than this, uh, force of gravity does influence the motion off the train. It would influence the motion of the train if we assume friction. However, since its magnetic train, So in the end, the train floats in the air a little bit due to magnetic forces, we assume that there is no friction, which makes our system easier. And so the drink and move left and right And then you have this object here. This cube and this object, it can fall down from the sky randomly so the random position can be a random horizontal position. So let's say one object starts from here. It falls down and then next second another black object appears here or here, and it can also have a random height so it can be here or here. And then the force of gravity is also applied on that object, and so that object will fall. Now the objective of the train is then to do what? The train, What it does. It calculates the horizontal error. This is your X axis and write your ex dimension and where your object is. This is where your reference X is. So let's say maybe if this is zero, maybe you're XRs here says maybe it's five meters and then your train is at 15 meters, right? So what you do, you subtract x from X are so this is your target. This is where you wanna be, right? And this is where you currently are. And so, if you perform this operation x r minus, X what you get, you get an error and in this case this error would be negative. And so we also assume that in this direction, the excess positive. And if you go up, then why is positive? So if you go down, then why is negative? And if you go left, then X is also negative. And so when the object falls, the task of the train is to move quickly and stop here and catch the object. So this is the height here, the position why and it changes as a function of time. So as the object falls, also, the white position changes. And one more thing that we need to no is that the magnetic train, in order to move some kind off horizontal force, needs to be applied to it. And so this horizontal force is this F A sits it stands for f applied. And so it's produced by magnets in the magnetic system here. And so if the object is here, this, uh, apply force is applied to the train which makes the train move, and then the train will be here to catch the object. Now, if you have another situation where, for example, your object iss here right and you are here, then it's exactly the same situation. The only difference is that no, your error will be positive. Why? Because your ex are your target position is here, and then your current position is here. So your target position is bigger than your current position. And so when this object appears in the sky and starts falling down, then an error. Horizontal error is calculated by subtracting X from X R. And in this case you would have a positive error. And so the train would apply some kind of force by man. It's and fruit move here to catch it. Now, the question is how much force you apply in order to be here on time. You know, because if you apply a very little force, then you're not gonna make it, and the block will just fall through. But if you apply too much force, you will just overshoot, right? Who will just go? There you go too much to the right, and then you will miss the Plock. And so that's what we're gonna be now learning. And for this kind of time, Scott proportional controller is not quite enough because you will see that it will cause and overshoot a proportion control will cause the train to just shoot through the target. And so you will simply miss your target in that case. But a ped controller will be able to manage the situation. So we're gonna learn about that. So let's get started.
14. PID: Modelling the train with forces 2: So every time when you have some kind of control problem and every time you wanna design controller for your problem, he first start with the physical set up. So here you have your train, and then here you have your block that is falling down. So you wanna create this physical set up because then you will understand better what's going on. You can also put force vectors wherever you have them. So it's good to do it like this. However, in order to design at controller and so your control problem, it's then also good to put your problem in another form in this kind of four. So this is not a physical set up, but it's a good set up for control problems. So first of all, what you do, you take your system, which is your train, and that train has some kind of input, and it has some kind of output. Remember the system input is some kind off action that you can control, and it's produced by some kind off actuator or some kind of mortar, right? And then you use that input in order to influence the output, and the output is something that you measure, for example Sensors. So in this sense, in this case, we have our system. We have our train here, and what we're interested in measuring is our position. It's our horizontal position. Are exposition, right? So we measure the position, and so what we do, then we feed our position back and we compare it with target position, and then we calculate the error and note that the units are the same for everything. Right? So this is your current position where your train is at right now, and this is your reference position. It's where you want to trying to be and to stop, right? So it should stop there. And so then you calculate the air, and then the error also has the same units. And so what you want, you want to see that error into your controller? And by the way, when I said that the train also needs to stop at X R. This is the reason why the proportional controller in our situation wouldn't work because proportion controller would take the train to the target position. But the train wouldn't stop there. And I'm gonna explain it to you Mawr in a minute. But the point is that you calculate your horizontal error, your error in the X direction, and then you put it into your controller block. And right now it's like a black box. But we're gonna uncover it. We're gonna open the box, and we're gonna see that you will have a P I. D. Controller there. So we're going to design a PhD controller and it's gonna be instead of this box. And so this controller will then have an output which will then be fed into your system. So the output for the controller will be the input for the system. And so the before the system would be then the force, which will be produced by magnets over the train. And so the controller will trying to figure out the right amount of applied force in order to move this train to your target position. In other words, to make this error zero and so in control problems, it's good to put the problems in this kind off block form. It's very common to do that and now the question is OK, so what's our mathematical model for our system? Because now what we have to do. We first have to model our system, not our controller, but our system. We have to model it mathematically. How do we go from apply force to a position now before we move forward and just want to make it even more intuitive for you? See this form that we have right? It can be applied to many systems. Right now we have a train, but also when you have a water tank, then it's the same logic. You have some kind of input. In our case, it's a mass flow rate, which is created by water pump, and then on the other side. It's our system output, something that we measured by sensors with a magnetic train. The system input would be apply force created by magnets, and then our output is something that we measure. It's the position that we measure by sensors. It could also be a velocity. It's what we choose. OK, it's what's we choose here and what we choose here. It's up to us to decide. You can also have an airplane system and, for example, you can also have a robot ride. And so, in the case of a robot, then with sensors. You measure its position in X y, for example, or in X y Z. But in order to go to these positions first you need to apply some kind of torque to its joint mortars. Right? And so, in this case, the torque created by joint mortars would be it's the system input. And then the position would be the outputs, something that you measure. So this kind of logic can be applied to a lot of systems, and it's very common to do that in control engineering. But okay, let's now continue with creating and mathematical model for our systems to remember our system Now is this magnetic train. Our system input is applied force, and our output is our position in the X direction. So now our goal is to derive some kind off mo a mathematical mo for this train so that when you put your applied force into the model, it will somehow give you the position. And you need that in order to simulate your system in the computer so that you could accurately design your controller. OK, so let's start what could be our apply force. So what is the force exactly? well, if you have a momentum, momentum is mass off a body times the velocity of a body, so that's a momentum. The second Law of Mutant says that force is the derivative off the momentum or the change of momentum would respect the time. Now you've heard that it might be the mass times acceleration, but mass times acceleration is Onley. In special cases, it's when your mass doesn't change when it's constant. The most general rule is the change of momentum with respect to time. And so when you apply the product rule, then you first take a derivative off em with respect teases how much your mass changes. Then you multiplied by your velocity, and then you take the same thing with velocity. You take the derivative of the velocity with respect to time and times mass. Now, since our magnetic train has a constant mass, it doesn't change is a function of time. Then this entire term will become zero. So you will Onley be left with this term. And as you can see, this term is mass times acceleration because DVD T is acceleration. Now, if we had a rocket instead of a train or an airplane. So when a rocket or an airplane flies than it consumes fuel, right, And when you consume fuel, then your mass changes. In that case, this term would not be zero. But in our case, it zero all right, so our apply force could then be written in this form. The reason why I put here apply force is because it's the only force in this X direction. So if we had another force, then we would have to I add subtract these force vectors and then you would have some kind of net force, and then you would have, ah, net force here. But right now we only have the apply force. So we know that our apply force is mass times acceleration. So what we can do next is that we can take this m and we can put it on the other side and down in the denominator place. So you would have our acceleration equals one over m times the apply force, right? And then the applying force is a function of time
15. PID: Going from system input to system output using numerical integration: So next what you do you take the integral. So what you have here, you have this exploration access and then you have the time access. And so this curve here and is just for illustrative purposes is just a random curve. It doesn't represent anything right now, but we can assume that this curve is then our function and the function in the mathematical form would be the acceleration DVD T equals one over m times, your applied force, which itself is a function of time. Right. So you could imagine that this could be, like two times t cubed or three times t squared. If this axis is your time axes and this axis is your acceleration access, then let's see if we say that this is our function, then a question to you is how would we go from this four tool velocity, right, because this is acceleration. But exploration is the change of velocity with respect to time prices, DVD T. So, in order to go from D v d. T two v two velocity, then you do anti derivative, which is an interval. And mathematically, it would look something like this. So if you're acceleration is DVD T, and you make it equal to one over m times your apply force, then what you do. You put your delta t on this side on to the right side and you will be left with d V equals one over m, and then this expression and then your delta T would be here in the end. And so when you take the interval of it, then you put your interval operator here. And so this is from where you start and this is where you finish. In this case, you start from an initial velocity. It doesn't have to be that your train at the beginning is addressed. Maybe your train already has some kind of velocity if it doesn't have any kind of velocity than you would put zero here. But let's say if it already travels five meters per second before you hit the counter, then that would be your initial velocity here and then your final velocity doesn't have to be a specific number. It doesn't have to be ah, constant number. You can treat it as a variable variable. That change is a function of time. So, in other words, you could treated like Okay, I take the integral from two meters per second to five meters per second or I take the integral from two meters per second to V. That changes as a function of time. And so on the other side you put another integral operator here. Since Mass is constant, the mass doesn't change. With respect to time, you're taking the integral with respect to time here. That's why you have the here, DT. And because your mass doesn't change with respect to time, you can put it outside of the interval. But you're forced does change with respect to time. So it stays within the integral. And so you integrate it from zero to t. So you started counter and zero seconds up until whatever t you have. If your final T would be five seconds there, here, you would have velocity at five seconds. If your final T was 10 seconds here you will have velocity at 10 seconds. Okay, Next. If you know, integrate this part, then you would have your VT miners your initial velocity. Right? So this is your variable. That changes as a function of time. Mine is your initial velocity and you leave this part unchanged, then you simply take this initial velocity and you put it on the other side. And so that's how you have your velocity as a function of time equals your initial velocity , Plus this entire term. And now, since we don't know what this function is and we have to implement this thing in the code anyway, then we're gonna transform. This continues for this continues mathematical form into this discreet for so this is a discrete mathematical form and this is something that you can directly apply into your coat . You can do it a inside of four loop or while loop. And so when we worked with a water tank example then I showed you how we can go from the continuous form to the discrete for so here. Now we work with these time intervals. So our time interval was 0.2 seconds. So then this is our present, right? And then this is our past 0.2 seconds ago. And again, this is Arpanet 0.2 seconds ago. And this is our present here, T j. Right? And so if you want numerically integrate, then you have something like this working as a loop. Now what we have we have our velocity as a function of time. Right? But this is not our system. What was our system? Our system was a position nav velocity, not meters per second. But our position So it's not enough what we have done so far. Right now, we only have our velocity as a function of time. Right? So this DX DT, it's V right? It's our velocity. And now what we have. We have our velocity as a function of time. But our main goal wants to get X as a function of time. So what do we do? Well, we take another integral right, So we have another function now. So this is our velocity that we got by taking them to grow off this function. So now we have this function here and since V is DX, DT is the change of position with respect to time. If we want to get a position as a function of time who want to get X is a function of time . So what do we do? We take another integral All right. And we now integrate are you lost. Now we have a velocity as a function of time. And so we integrate that. And then we get our X So it would look something like this. So the same logic is just instead off these You have excess here and here. Instead, off the force, you would have velocity. And so you take this integral like this exactly in the same way, right? Exactly. In the same way on Lee. Now you have your initial position are the initial velocity but initial position and then your changing final position. And here, instead of one over m times C Air Force, you simply have your velocity. And so you integrated like this. And now you have your position as a function of time. And this is your discreet for right now you're taking the integral numerically that you can apply in the code. And so what we have done here we have taken to integral. So this could be our mathematical mall off our train system. So our system input waas the apply force that was produced by magnets, right? Next what we did We divided this force by one over m. And then what? We got we got our acceleration. Because if you divide force by am, then you get your acceleration. Then we took the integral. We got our velocity, and then we took another integral. And we got our position, okay. And our mathematical model for our system would be all this. So the continuous form and then the disc reform here. Okay. And also here you would have the continues form and the disc reform. Our mathematical model would then consist off to parts, right? It would consist off to parts continuously, and it would consist of two parts discreetly. So if you want to represent your mathematical mull in a continues way, then you would have two equations here. One, The question is here That takes you from FAA to DX DT. And then the other equation here is to go from the X DT two x t. And this is the same thing. Onley in the discreet way. All right, so, no, let's try to apply our proportional controller what we had in the water tank. Example to this example. Let's see how it works out seeing the next video
16. PID: Magnetic train simulation - proportional controller: Okay, let's carry on with our PID exercise. So right now you see a simulation of the train and we have taken away the inclination. So right now the train only goes to the left and to the right. And the controller that I have applied to this train is the proportional controller. If the same controller that we had applied previously in the water tank example is the same controller. And so I've also switched off the random function that makes the block appear randomly. So its initial position starts only from here. We want to see whether the proportional controller is able to do the task and catch the block or not. And as you can see, it's now really doing its job. And it is trying, it is trying to be where the block is. It is trying to reduce the error. However, the problem is that the train is not stopping where it should stop, it is overshooting. And if you're very lucky, you might cache the block on the go if your timing is right, but that's not the goal. The train should stop here and then catch the falling block. So the proportional controller here is now working. And now we need to examine why it's now working. And after we know the reason, we can then design our controller to or modify our controller to complete the task and to eliminate the shortcomings of the proportional controller. Alright, so let's see that in the next video.
17. PID: Proportional controller overshoot explanation 1: So what we saw in our simulation was our train oscillating around this reference point here. So here in the middle we have our reference point. And the train was oscillating around it. So it first starts going from here in this direction. While it's on this side of the reference line, you have force directed to the left side. Then the train goes here as it goes to the left. But since it's on the left side of the reference frame, you have force to the right, right, because now the error is positive. Here the error was negative in the first case. In the second case the error is positive, so the force is also in the positive direction, even though the train itself is going to the left. Now the train is going back to the right, but it's still on this side of the reference lines, so the force is also to the right. And now when the train crosses this reference line, then even though the train goes to the right, but the force vector is to the left. The error here is again negative. So the error on this side is positive because it's x, r minus x. And then on this side the error is negative. So that's how the proportional controller controls the force for the train. But now let's analyze the behavior of the error. So if you look at this picture, and if you look at this picture, then essentially this graph represents what's happening here. As you start moving from this point to the left, at the beginning, you have a negative error, right? Because you are on this side of the reference line, your reference position minus your actual position will give you negative error. And that's why you start from here, right? And then as you move and you cross this reference line, when you are on this side, then your error is positive. So you are here. Now. This block here, right? You are also on this side of the reference line, on the left side. So your error here is also positive. So it would be somewhere here. And when you are here on the right side of the reference line, then you will be here. Alright? So as this block moves like this, you can see how your error changes as a function of time. First negative, then positive, and then negative. Now one thing that I want to show you is that if you have a proportional error, then what you do with your error, u multiplied by K p, and then you get your force, right. But then your acceleration is force divided by mass. So your acceleration is actually KP divided by m multiplied by e, and this K p over m, This is also a constant number, right? So this is also some kind of constant. So essentially you are multiplying E by some kind of constant, which is k p over m, and you get acceleration. That means that your acceleration function, which is this one in red, has the same shape like the error function, right? If you look at it, this is your error function and this is your acceleration function in red. And it has the same shape. Now, of course, it has a different magnitude because you multiply the error by some kind of number, which was k p over m. So you might have a different amplitude here, either bigger or smaller. However, the shape is the same. So this is your acceleration function, right? And now, in order to understand why that block was overshooting, We need to go from acceleration, first of all to velocity.
18. PID: Proportional controller overshoot explanation 2: So now I'm going to try to explain to you why the train overshoots when it reaches its target position. So this is the place where I would ask you to pay really close attention to what I'm telling you because you need to focus on what I'm about to tell you in order to understand what I mean. So let's start. So first of all, that was our case, right? The train started from here, it went here, and then back here, you had negative error here. You have positive error here, positive error here, negative error here. You can see it on this graph. Alright? Now, when you have your error function, you get your force out of it. You get your acceleration. If you divide FA by m, force by mass. Or you can just get your acceleration if you multiply your error by this constant, which is k p over m, It's the same thing. That means that your acceleration function has the same shape like the error function, right? So when your error is 0 meters, when you are here, when you are at time equals two seconds, and also time equals six seconds. But let's focus on time equals two seconds, right? When your error is 0 here, when you're here, then your acceleration is also 0 meters per second squared. Because your force is 0 Newtons. The applied force here is 0 Newtons because your error is 0. Okay? What does it mean? If you integrate acceleration as a function of time? If you integrate it, then you get your velocity. What is acceleration? Acceleration is the change of velocity with respect to time, right? So when your acceleration is 0, then for that brief moment of time, your velocity to the velocity of your train. For that brief moment of time, it stops changing. The slope of your velocity is 0, right? At time equals two seconds, the derivative of velocity with respect to time is 0, but then doesn't mean that the velocity itself is 0 meters per second. In fact, is very high here. It's negative, right? Now, what happens when you have a velocity as a function of time and you take the integral of that, what do you get then? You get position, right? So your position starts from here. You are on this side of the reference line. So this is the positive position, and then this is the negative position. And again, this is the positive position here, this function, it represents the position of your train. So the proportional controller, it makes sure that when error is 0, then your acceleration is 0. And in fact, it also makes sure that That your position is 0. However, the problem is that when your acceleration is 0, you have something in between. You don't go directly from acceleration to position. You first go from acceleration to velocity, and then from velocity go to position. So when your error term is 0, then your acceleration is 0. That means that your velocity at this point is not changing, but it doesn't mean that it's 0. Here, velocity is negative. Now when your velocity is not 0, and it is impossible that your train reaches its target position and just stays there. It can because your velocity is not 0. What is velocity? And velocity is the change of position with respect to time, right? It represents how your position changes. So if at time equals two seconds, your velocity is not 0, then what's going to happen? Obviously, you are going to continue driving in your direction. And the same thing here. At time equals six seconds, your error term is 0. That means your force and your acceleration is 0, and also your position is 0 meters, you are where you want to be. The problem is you don't stay there. Why? Because even though you're accelerations, 0 meters per second squared, the next step from acceleration is your velocity. Your velocity, however, even though at this time it's not changing, it has a 0 slope. Your slope here is 0, but u velocity itself, It's not 0. It's a positive value. And because your velocity is not 0 meters per second, it's impossible that your train reaches this point, this reference point, and then just stays there. It's impossible. Your velocity is not 0, so you continue driving forward. And that's why you see this overshoot. Because we control acceleration. We make acceleration 0 meters per second squared, but we don't take care of velocity. We don't make sure that our velocity is 0 meters per second here. And that's why we have this overshoot. What we want is something like this. So this is our position function. And if you look at this green line, so we want something like this, right? So we want that at time equals two seconds. When we reach our target position, we want to stay there, right? We don't want to overshoot. We want to stay in that position. In order to stay in that position, if you look at this green line, we need to make sure that our velocity also stays 0 at time equals two seconds.
19. PID: Proportional controller overshoot explanation 3: And the problem with the proportional controller is that the proportional controller is not powerful enough to achieve this kind of behavior in this system. Why? Because if you look at your system, then our system, our train system, it has two integrator operators, right? So you have to integration, you need to integral operators. You need the first one to go from acceleration to velocity and the second one to go from velocity to two position, right? And the problem with the proportional controller is that a proportional controller cannot handle two or more integrators, can only handle one integrator. So the proportional controller would work if, for example, our system was different. If for example, our system input was force. That would become an acceleration when we divide the force by mass, right? And then our system output would be velocity. So if I were to tell you that, OK, I don't care about the position of my train. I just want my train to reach five meters per second. So I want the velocity of my trained to be five meters per second. And I want it to stay there. And then my system input would be force. Then I could use a proportional controller. Then my proportional controller would make acceleration 0 when my velocity was five meters per second. Or for example, if I were to tell you that I care about position and I use velocity to control my position. Not enough force, not acceleration, but we lost the NSA that OK, I want my target position to be ten meters. And then I regulate, somehow I regulate velocity or of my system. And then my proportional controller would make velocities 0 when I reach my target position of ten meters. So your proportional controller would work if your system only had one integrator, and in our water tank system, you only had one integrator. Alright? You had a mass flow rate, and then on the other side you had the you had your volume and you only needed one integrator to go from mass flow rate to your volume. But now the system is more complicated because now first of all, you have apply force that you transform into acceleration by dividing the force by mass. That's okay. This is just a constant, but then you need to integrate your System two times in order to reach your system output, right? In order to get from acceleration to position, you need to integrate it twice. And for that, we need something additional. Proportional controller alone won't be able to cut it. So we need something additional. And the next thing that we're going to introduce is a derivative controller, which will be combined with the proportional controller. And you will see that when you combine them both, then they can handle two integrators. And then you can have something like this. So now let's look at the derivative controller and see how we can combine it with a proportional controller.
20. PID: Intro to Derivative Control: So how do we achieve the behavior of our system, of our train as we want it? How do we achieve this velocity function, this green one? And how do we achieve this exposition function? How do we use a derivative controller to achieve that? So now I'm going to show you what a derivative controller is and how you can combine it with a proportional controller in order to achieve a system response like that. And by system response, I mean how your system reacts to your input. How the output reacts to your input, which is force created by magnets in our case. So let's see. First of all, let's pay attention to this graph here. In red. This is our error function, right? Is the same thing that you saw before, that this is the error function in red. So if you take your error and you multiply it by KP, then before you got your force. And that force was then the force that the magnets applied to the train in order to move the train. But as we have seen, it's not enough. So we need something else. So we can use a derivative controller. So this is a derivative controller, right? So how do we get the derivative controller? And it's very easy. This is your error function and you take the derivative of your error function and then you get this blue function, right? So this blue one is d e d t. And the reason why you have x here is because we are dealing with the horizontal error, right? So this is your d, d t, So this is your derivative. This is how your error changes with respect to time. So you have this function, this blue function, and you multiply it by another constant, which is k, d and KP and KD. In both cases, they are slopes. There are different numbers, but the logic is the same, their slopes. And so in red, you have a proportional controller, and in blue you have the derivative controller. And so if you add them together, the proportional and the derivative controller, then It's a PD controller, proportional derivative controller. And when you add them both together, then you will get your force, your final force that magnets will create in order to move the train. But let's look at it a little bit closer. So now you know how to create the derivative controller. If you look at it, then, okay, so this is the proportional part and this is the derivative part. So note that the difference here is that. Here you have error in the proportional part, you have error and in the derivative part, you have the change vector with respect to time, right? So now this axis is DDT. And if you multiply it by some kind of slope, then you get the derivative part of your force. And here's your proportional part of your force. And if you add them together, then you have your final force. Now, why is useful? So let's see. We start moving from here and then we move here. So this block still moves to the left. Then, now here this block moves to the right. And here the block still moves to the right. Okay? So if you look at this dashed line, it indicates from where this block is going. So here you know that the block is moving to the left. Here, it's moving to the left here, it's moving back. This is where the block has just recently been, so it's moving in that direction. And here the dashed line is here, which means that the block is moving to the right. So it's moving that way. If you look at this graph, then what you can see is that when you are in the first case, let's divide this graph into four parts, right? So we have four parts because here we also have four parts. You have here where you move to the left, then you are on the other side of the reference line where you still moved to the left, which slow down. Here you go back, you move to the right towards the reference line. And then here you are again on the other side of the reference line, but you move away from the reference line. So you have four stages here. And these four stages, they can be seen here. So we divide this plot into four parts. So we divide it with the orange dashed line. Alright, so this is the first part, the second, the third, and then the fourth. So in the first part, we move towards the reference line. So let's see. If we move towards the reference line, then our proportional controller gives us a negative error and therefore a negative force. So you have a negative force, right? You have forced to the left and to the left means negative. However, if you now add this derivative part, then the derivative part, we'll give you a positive because even though your error here is negative, but the slope in this section is positive and therefore, the derivative here is a positive value and you multiply it by k d, so it will give you a positive number. Therefore, there will be a component of the total force FA, that is positive in this direction. Now this is very good because before we applied our derivative controller, we only had our proportional controller, so we only have one force pushing this trend towards the reference line. But now what we have, we have a proportional part that is pushing you towards the reference line, but then you have this derivative part that is slowing it down. Now, if we now go to the second section, now we're here and it's this one right here. We are on the other side of the reference line, but we move away from the reference line. And what happens here is that both the error term and the derivative of the error, both of them are positive. That means that the two force components are positive in this direction. So think about it now, your train is moving away from the reference line, but you have to force components pulling it towards the reference line, right? So that means that this train, even though it's moving away from the reference line, these two force components are slowing it down and pulling it towards the reference line. That means that this train is slowing down faster than it was just in the case of a proportional controller. Now, the next section would be this one. So that corresponds to this situation where you now go towards the reference line, right? Now you move towards the reference line. And so the proportional controller pulls you towards the reference line, but the derivative part points in another direction, so it slows your train down. So you still move towards your reference line, but you are slowing down. And you can see from this graph that your error term is positive, but the derivative of your error is negative because you have a negative slope here, right? So this blue line is the slope of the red line. And so here the derivative of your error is negative. Therefore you force vector of the derivative part is negative in this direction. And so it slows your trained down as you get closer and closer to your reference point. And finally, when you are again on this side of the reference line, you move away from your reference line. But you have both the error and the derivative of the error. They are both negative. So you have two force components pulling the train towards the reference line. So you can see that the derivative part, in this case, it's working in your advantage. Ok? And the thing about the proportional and the derivative part is that you can choose what values you choose for KP and KD. Note one thing, KP and KD, they have different units. Kp is newton per meters because you have error here and then you have force here. But in terms of the derivative controller, here, you have the derivative of the error with respect to time. And here you have force. Therefore here, the units here are meters per second, and the units here are Newtons. So your KD is actually Newton per meters per second. However, one thing that I want to explain to you is that as you design your controller, right, you can choose the values for KP and KD, and it's at your discretion. And depending on the system, you try to find the right values. And that's called controller tuning.
21. PID: Tuning the controller: So one thing that I want to talk about now is about controller tuning. What does it mean when I talk about controller tuning? In this case, it only means that we try to find the right value for KP and KD in order to achieve our target in the best possible way. Kp and KD, What are they? They're, they're just slopes, right? So if you choose a strong value for K, p, then you will have very high slope here. And if you choose a very low value for K D, then you will have a very small slope here. So in that case, the proportional part in your controller would be stronger than your derivative part and vice versa. If you choose a strong value for your K D and the weak value for your KP, then the derivative part of the controller will be stronger and then the proportional part will be weaker. And so you can regulate how strong is the proportional part in your overall controller and how strong is your derivative part in your overall controller. And that will of course affect your system behavior. For example, if you say that your proportional controller is very strong, right? But you want your derivative controller to be weak, then you choose K p to be a big number in KD to be a small number. And then the result of that would be that here you have very large force vector, the red one, and then the blue force vector would be smaller. And in that case, okay, this blue force vector would still slow down your train in this condition. However, the slowing down effect would not be that strong. However, if you do it vice versa, you choose k to be a big value and you make your derivative part of your controller very strong. And then the proportional part week, then you will have a small force vector here, pulling the train towards the reference line, but you will have bigger vector in the other direction. And so the slowing down effect will be bigger. Now you might think that if you choose a KD factor as a very big value, then you will make your derivative part very big compared to you, your proportional part. And then you would have a very huge vector here, the blue one and then a small vector here, the red one. And so according to this, you might think that the train might go in another direction. It might go to the right away from the reference line. However, that's not what's going to happen because. Remember that the derivative part doesn't only depend on this K D value, it's KD times the change of the error with respect to time. All right? And this, this derivative controller, the derivative part, has this effect of resistance. So the train wants to go towards the reference line, but the blue line here, the derivative part, it resists. So at the beginning you have your error here, right? And if you're KD is very strong, then what it will do, it will resist. That means that the train will be moving very slowly and it's error will change very slowly. If it's error changes very slowly, then even if you have a strong value here, you have a big value here. But because the error changes very slowly, you will have an extremely small value here. So that is why you won't have a situation where you have a big vector here and the small vector here, because in a way they are linked, linked through the error terms, right? So a strong Cady will make the error e change very slowly. And if the error e changes very slowly, then d, d t will be very small. Let me say it again. If KD is very big, it has the resistive nature. So it will do, it will now allow the train to move very fast, right? So because at the beginning, your error, it's negative, but its slope is pretty much 0, right? So even though you have a very strong value here, but at the very beginning, your slope of the error is 0. That means that whatever value you have here, this term here is 0. So this entire term will be 0 at time equals 0 seconds. And only when the error starts changing, then this term will appear. And because this term has this resistive nature here, if you choose a strong KD, it will cause the error to change very slowly. And because of that, you will have a very small number here. So even if you have a big number here, this entire term, KD times D DT is still won't cause a situation where the train would just move to the right. So now I'm going to show you a simulation where we can tune a little bit of KP's and KD is and we see how they react. Okay, so see you in the next video.
22. PID: Proportional & Derivative controller & magnetic train simulation in Python: So I'm going to present a simulation now. And this is the code for it. And you can download this code in this section. So feel free to download it. Feel free to studied reverse engineering. You can look at what I did. You can experiment. The only thing is that if you want this code to work for sure, I only recommend you to change the seven variables here at the beginning of the code. And if you want to change something else, then it's better if you make a copy of this code and then experiment the copy, right? So here we can change KP and KD, and the next one will be KI, So the integral part, but right now we're going to focus on KP and KD. So I choose K p to be 300, K d to be 100. The mass of the train is 100 kilograms. We are on Earth. The acceleration due to gravity is ten meters per second squared. Right now the inclination angle is 0 radians. And so let's see how the system is going to react. Well, it managed to catch it. That's very good. So you can see that now it does overshoot because KP still pretty strong compared to K d. But KD, the derivative controller is able to, is able to slow down the train and damp out this oscillation. And by the way here you have, you have the derivative of the error with respect to time. So this is the error, right? And this is the derivative of the error with respect to time. So let's test more. For example, if I say that KD is 50, but now the resistive nature is weaker. So if it's weaker than you are going to overshoot more and you will fail, right? How about if we make them equal three hundred and three hundred? So in this case we have KP and KD. There are equal both 300. And you can see that for this specific case, the PD controller is pretty well tuned. So it is able to slow down and stop where it is opposed to stop and then catch this falling cube, right? So it is able to damp out the oscillation of the train pretty well. And so you can see this is the error here. And you can see that it's very smoothly becomes 0. And this is the derivative of the error with respect to time. And also it is very smooth. And it also becomes 0 very smoothly, which is like the error. Now, let's see what's going to happen if instead of. Three hundred and three hundred, we're gonna make KP 300, KD, 3 thousand, so ten times stronger. So now KD is going to be very strong and the effect of the derivative controller is going to be very strong. And let's see what's going to happen. As you can see, the resistive effect of the derivative controller is so big that it doesn't let the proportional controller to move the train towards the block. So the train moves towards the block very slowly and therefore it is unable to catch it. So like we talked before, even though KD is a lot bigger than KP, The train is not moving to the other side, right? It's not moving to the right. Why? Because in the derivative part, KD is multiplied by this, multiplied by by the derivative of the error with respect to time. And at the beginning, the derivative is 0. And because it has such a strong resistance effect, the train is not able to star moving fast enough and therefore, the change of the error is not big enough. So there are linked in this sense. The greater your KD, the less your error will change. And so the end result is that your train will, it will move towards your blog, but in a very slow fashion. However, there's one thing that you have to keep in mind when you design these kinds of controllers. You cannot put just like random numbers, because if you put completely random numbers, then your controller can go crazy. So I'm going to give you an example, 7 thousand. Let's see what's going to happen now. So you see, now the system is becoming unstable. Ok? So it's becoming unstable. And that's because when you have values that don't make sense that are very big or very small, then you know, what's happening here is that you have a code running, right? And your code is always calculating something, your controller is always calculating something. So if you have weird values, then it might become unstable. It might start giving you big values in some areas of the code, in some areas of the controller, that won't make sense and they just make your system unstable. So for example, if I make it 10 thousand, then it will be more apparent. You see, like it just doesn't make sense. So when you design your controllers, you shouldn't put whatever numbers you want. So this is just something to watch out for in the future. And now I'm going to turn on the random function to see if the block appears randomly. Will the controller be able to catch it? So what I'm gonna do now, I'm going to make KDE 250, and I'm gonna make trials five. That means that there will be five random positions from where the block will start falling down. And what I have to do, I have change one thing here. So here I have to comment this part and I have to turn on the random function. And let's see. Okay, is able to catch this one this 13 times more. Now they appear randomly. So it seems that when your KP is 300 and KD is 250, then the controller in this environment works pretty well. Okay, so in the next video, we're going to start discussing about the last part of the PID controller, the integral part, because there are situations where even proportional and derivative controller combined cannot handle. So we're going to discuss one specific problem called the steady-state error. I'm going to show you why the proportional and the derivative controller can't solve a steady-state error. And what the steady-state error is, and how the integral controller can solve it. And then we're going to combine them all together and you will see the entire picture. Now in the next part, you will have an inclination, so the rails will go up diagonally.
23. PID: Intro to Integral Control: welcome back. So now we're going to start learning about the final part of a P I. D. Controller, the interval part. And this is what it stands for P i d. Proportional, integral and derivative controller. So we have so far covered the proportional part and then the derivative part. But we still need to cover one more part, which is the integral part. Let me show you one example where that integral part can be relevant. So now we're going to include and angle here. So now the rails, they don't Onley go horizontally. They also span horizontally and vertically, right? So now the train not only can go left and right, but it can also go up and down. Right? So now let's let's think about what it means. First of all, if we start putting forces on our bodies, then okay, we still have this apply force that is a plight by the magnets to the train. But now we also have a force of gravity now, before force of gravity. It didn't matter because since we ignored friction because it's a magnetic train and so it basically the levitates a little bit. So there is no friction, almost no friction. But it's so small that we can just neglect it, and here as well, we neglect friction. However, what we can't ignore anymore is force of gravity. Why? Because force gravity acts on this train vertically. However, because this train is on rails that are at an angle, you have to take this force of gravity and you have to decompose it into a component that is perpendicular to the rails, right and which is tangential to the rails. Now the component that is perpendicular to the rails is this one, and we call it the gravity normal force and you get it by multiplying course I in theater by force of gravity. This is our force of gravity here, right? So essentially, it's the mass of the train multiplied by G, which on earth is 10 meters per second square or more precisely 9.81 meters per second squared. And this theater here is the same like this Tita here. So if you want to decompose this vector into the normal component and the tangential component and the normal component would be every tee times course in theatre and then the tangential component would be if g. Times Science Theater And now you can shift these vectors and what we're gonna do, We're just going to shift this vector here. And so this normal component off the gravity force, it is balanced out by the normal force. Right? So it's just like when you're on the ground, you don't go through the ground because the ground applies normal force to you, which is equal but opposite to the force of gravity. So that's why you don't accelerate when you stand on the land. However, in this case, since the train is on the inclination than the normal component is not completely down, it's in this direction, and it is balanced out by the normal force Now. The tangential force of the gravity force, however, is the force that if you don't do anything, it will make the train slide down, all right? And so now you have this extra force that you need to think about when you analyze your system and let me just show you assimilation, where I'm going to switch off all other forces, and I'm just gonna let the tangential force to do its thing. All right. See, in the next video
24. PID: Python magnetic train simulation at an inclination angle: So right now I have switched off all the components of your applied force. So I have made KP, KD, and k i is 0. So there is no applied force. And because there is no inclination, because the rails are completely horizontal, the train is not moving anywhere, right? So now what we're going to do, we're going to introduce a 15 degree angle. Alright? So let's do it. 15 degree angle. So 15 degrees in radians is pi over 12. And so, let's see what's going to happen now. So you can see that this 15 degree angle, there is no tangential component. For the force of gravity. There is a normal component that does not affect the motion of the train. However, the tangential component is affecting it and it is accelerating away. I thought that it was going to catch the cube. So this tangential component of the gravity force is going to now make the train accelerate along the rails downward. So now when you apply your force produced by magnets, you have to take into account the tangential component of the gravity force. All right, but let's go back to the equations. I'll see you in the next video.
25. PID: Mathematical modelling of the train with the inclination angle 1: So when we look at this drawing, then we have now to forces along the rails. Our falling object are falling. Cube is here. Our train is here. So that means that our error is this one. All right, there's the distance and it's a negative error. And so you have the force from gravity. That then gentle part it's in this direction and then you also have this applied force produced by magnets also in this direction. So what really happens is that you have to sum them up the tangential component off the gravity force and then the applied force. And then you will get a net force and that force that you can now decompose into x component. And why component? Because at least in my coat, the calculations are made separately in the X direction and in the Y direction. And there are several ways you can do it. You can also define a different reference frame. You can say that. Okay, this is your ex, and this is your why. But I didn't do that. So I prefer to just a decompose this vector into X and y I still use this as my X axis and this as my y axis. So this is your net force here. All right, so now if you want to know the acceleration off your train, then you need to take this net force, and then you divide it by the mass off this train, and then you get the acceleration, the real acceleration off this train. Now, if we have another situation where the cube is here, right, then you have a positive error. And so the tangential component off your gravity force is still in this direction. However, your applied force by the magnets, it's in another direction. So in this case, what happens is that your net force will be smaller because your net force will be if a miner's f g t. Because they are in the opposite direction. So the difference is F net. And that just means that in this situation, your apply force has to be greater in order to go up because it also needs to counter this tangential gravity force. Okay, so this is the set up off our world. And if you want to derive equations for the situation, the logic is exactly the same. Now, the difference here now is that because you have two dimensions, right? And because at least I do it using still this axis as X And this axis is why I do it in two dimensions. Because of that, what you have to do, you have to do the same thing like you did before on Lee. You have to do it twice in the X dimension, and you have to do it in the wider mention so essentially what you do, you take your f net and then you decompose it. If Net accent definite why and you work with them separately. And so you first of all get the acceleration in the X dimension and in the wider mention, then you get your velocity in the X dimension and why the mention? And then you get your exposition and why position? So it's again. It's a double integration, but you just do everything twice in the X and y dimension. And now let's look at the specific case where I'm going to show you why you would need an interval controller
26. PID: Mathematical modelling of the train with the inclination angle 2: All right, so now let's look at a specific case. Imagine that this is where your block is, right? And you are exactly, you're exactly where you have to be. Okay? Your block is here and you're exactly where you have to be. So what happens when you're exactly where you have to be? Well, your error is 0 meters, right? And you are at rest. If you are at rest, then also your e dot. So your error derivative with respect to time, it's also 0 meters per second, right? Now, the angle here was 0 degrees or 0 radians. If we only had this horizontal problem, if we didn't have this force of gravity, this tangential component of L, then we wouldn't care, then everything would be nice. However, now we have a problem because let's think about it. If your error is 0 meters and if your e dot is 0 meters per second, that means that if you look at your proportional derivative controller, then this term is 0 and this term is 0. That means that your apply force is 00 Newtons. Okay? Now, if you apply force is 0 Newtons, but you have this force of gravity, this tangential component of the gravity force here. But your error in your e dot r 0, that means that there is no other force to counteract this gravity force in this direction, right? So what's going to happen in this case, the train will start slipping down. And so when it started slipping down, then your error in your e dot there, not 0 anymore. So the black would be the proportional part and then the red would be the derivative part. So as you go away from where you have to be from your reference line, now, there is an error, and that error will produce force in the positive direction, right? However, if you sum them up, they're still smaller than this gravity force. So because of that, because the gravity force in this direction is still greater than the addition of these two forces to the right. Because of that, the train will still continue sliding down. Okay? But now let's imagine that when it slides down a little bit more, the error will increase even more. So the applied force will increase because remember we have proportional controller. So at least the proportional part will always increase the further you get from your reference line. So at some point, you reach a point where the total force, the applied force, is equal to your tangential force. Ok? So now the forces are equal but in the opposite direction. And now what happens is that the train is at rest. When the train is at rest, then the error doesn't change anymore, right? If the error doesn't change anymore than the derivative part of the applied force is 0. Because the derivative part of the applied force can only exist when the error changes, but since the train is at rest, because both forces are equal in magnitude, but they're in the opposite direction. Because of that, you don't have the derivative part anymore, but your proportional part, the proportional part of your apply force is equal to the tangential part of the gravity force. Now if the forces are equal, then while you're kind of trapped R into, your controller, doesn't know what to do. Because it can only increase the force if your error changes, but it's not changing. So it's trapped. So this is now one situation where it's not enough to have a proportional controller and it's not enough to have a derivative controller. So you need something else. And that's why you need the integral controller and them, I'm going to explain to you how it works. But again, just to make you really understand what's going on, the train is not moving. Therefore, the error that you have here is fixed. Because it's fixed. The derivative part is 0 and the proportional part of the applied force is not 0. It's a number, but this number cannot change this number. The proportional part produces force which is exactly equal in magnitude to the force of gravity. And because of that, the train can move. And so because of that fact, error stays the same. And because of that fact, your applied force cannot change, so you're just stuck. Okay? And this kind of phenomena has a name. It's called the steady-state error. And to counter that steady-state error, there is another idea.
27. PID: Proportional, Derivative, Integral Control combined: the idea to counter this kind of situation The steady state error For that, we need to use an integral controller. So let's look at this graph here. So you have two graphs here. Okay, So first of all in the opera graph, the first thing that you see you see the error function. Okay, so if we start looking at our story again starting from the beginning, where we were at the place where error and then e dot Where zero. Then on this draft, it's this place here. Okay? Now, as we start sliding down, we had two components so far apply force, right, The derivative part and then also the proportional part. So this is this one. We divide this graph into several sections. And so this first section from here from the beginning until this dash line, it's the time period that it takes for the train to go from this initial position up until the position where your forces are balanced and you get stuck. So this is like the intermediate timeframe. During that intermediate time frame, you have disproportional. And then you have this this derivative apply force, right? And make sense that both of them there pointed towards the right because your error is positive, and then your e dot is positive. And you also assume that you choose K. P and K d as positive numbers, and that's what we always assume. I mean, you can also choose negative numbers for them, but then you would reverse everything. But in this example, we assume that KP and Katie are always positive. And so the error and e dot there positive. So both forces there pointed towards the right direction. No stunning from here. This is where you get trapped. So from here, till here you have the steady state error and this is the time access, by the way. So this is the evolution off your error term and your e dot So from this point, up until this point, we assume that there is no interval controller. Right? So it's strictly KP times e plus Katie times e dot So we ignore this final term, which is the interval controller, right? So from here to here, there is no interval controller from here. Still, here you have the steady state air. This is when your error doesn't change, which means that your e 0.0, which means that you only have your proportional controller working, right? And there you go. You only have this proportional controller to the right side. And so you're trapped now, in order to get out of the trap. At this point here we turn on our interval controller and the integral controller is just like proportional and the derivative controller. It also has a constant K i que i is also like a slope. So it's also a number that you choose. And now you multiply this gay I number by error not by the derivative of the error, but by the integral of deer. Right? So when you integrate the error function as a function of time, then that just means that you sum up the area under the curve off the air, a function, and you can look at this graph. So here your error increases. And then as you sum up the area under the era curve, this function is the integral of the error. So continuously increases because it's a summation off what you have here. And so when you're in this section, that's when your error doesn't change, right? Your hair stays the same and your e dot because of that is zero. However, what changes is the integral off your error because even though you're ever is the same but the time still ticking. And so as time goes by, you continuously scan the area under the curve off the error function, right, And you continuously some up the area under the curve. And this summation he's shown here. So you see, even though your error is constant but the integral off your error is not constant. And so starting from this point, we turn on our interval controller. So now we have a complete p I d. Control we have are proportional part are derivative part and our integral part. Okay, And now when you're trapped because your forces were balanced, right When you turn on your interval controller, which is here, then you will have your integral off e this one you multiplied by K I. So you will have an additional force towards your reference line. So you see, you were trapped before because you're proportional controller was equal to your tangential gravity force. But now all of a sudden you have this extra force that comes from the interval part. So now your entire force to the right end up is greater, So your train will start moving up towards your reference line. So what happens next is that as you get closer to your reference line, your error starts going down, right? It makes sense because you started going towards your reference line. So the distance between your train and the block, the horizontal distance is decreasing. So you're error goes down when your error goes down. That means that your e dot is negative, right? And because you have a leaner function here, then the derivative of it is just a constant value. But it's negative. And that's why the derivative part off your P I d controller points to the left here, your error still positive. So you're proportional part points to the right and also your integral part. You have the summation which is positive here. So it also points to the right now, at some point you reach your reference line, right? You reach this point, you're here. But let's say that you overshoot a little bit, right? Nothing is perfect. So you overshoot a little bit. So now you are on the other side off this reference line. Right? And so now you have a negative ever. You have a negative ever. But you're slope is also negative. So both your proportional and the derivative forces, they point to the left. But as you can see, even though your error is now negative, which means that your integral off your error now starts going down right, But it's still positive, So the integral parts still points to the right. Now, here again, you are on this side of their reference line. However, now you move back towards the reference line, okay, and because of that, your error it's negative. But it's decreasing. And so your e dot it's positive, right? And your integral part is also positive. So that's why you see that your proportional force is to the left, but you derivative force and your interval force art to the right. And now last assume that you finally reach the place where you have to be the place where you have your block. Okay. And again, like at the beginning, your error is zero your e 00.0 right, And you can see from here that's where you reach that place. This is now your actual reference line and you're ever zero the derivative of your error zero. But now you don't slide back anymore, right? You stay where you're supposed to stay. Why? Because now you also have this integral part off your controller, and that integral part will provide the force that has the same magnitude like the force of gravity in the tangential direction. It has the same magnitude, but it's in the opposite direction. And so now you're forces are balanced and you stay exactly where you're supposed to stay. And that happens because even though your e and e dot r zero, but your integral off your error is not zero, why is it not zero? It's constant, right, because you're error now is zero. So when you integrate your error thing to grow, if you're error doesn't change because your error zero the time as a function of time. But the integral of your air is not zero because you see the thing with Integral says that it doesn't Onley take into account the present right. It also takes into account the past the past information the final result off your error integration depends on what you're ever is now and what it waas in the past. So in a way, you can think of the integral as a reflection off what your variables did in the past. So even though right now your error is zero. But it wasn't zero in the past. And that's why the end result of your integration is not zero. So it has some kind of number. And if you multiplied by K, I, then you will have this term. And so when when you're where you're supposed to be, then you're proportional term, and your derivative term will be both zero. And your train will only rely on this term on this K I times integral e d t. So again, when you're where you're supposed to be, you're trained on Lee the lies on the last term because the other terms will be zero. And the reason why the last term is not zero is because the integral off your error, even though it's not changing anymore. But it's not zero because it also takes in into account information off the error from the past. Okay, so an integral is like an evolution. Think of the integral like an evolution of something. And that's how the inter go part enables your train to actually stay where it is supposed to stay. All right, So now the integral part provides you with this force necessary. Keep your train where it is supposed to stay and to counter this tangential force of gravity. And that's why you need the integral part. Now let's put everything together. If you wanna look at your P I D controller in a schematic way, then it's very convenient to look at it like this. You have your error and this error is fed through the KP number. So this is the proportional part now. The error is also fed through the d DT operator. So this is the derivative operator. You have e dot the derivative of era with respect to time or the change of error was respected. Time you multiply that by K. D. Right, This is your derivative part and then your error is fed also through the integral operator . And then you have your integrated error or the summation off the areas under the curve. In other words, you have this thing after you go through the integral operator and you multiply that by K I . You summed them all up and you have your apply force your tool, apply force and so you can tune the controller by choosing which part of the controller you want to be stronger and which one you want to be weaker so you can put a strong value here and weaker values here and here, or vice versa. It depends on the system. Each system is different, and it requires you to understand your system properly, and it requires a lot of experimenting and experience. But in a way, that's what control of tuning means. Now, in the next video, I'm gonna introduce one a small little part in our control, which is not part of a PhD controller, but the small extra part to make our controller. Let's say a little bit better, So see you in the next video
28. PID: extra component in the controller to deal with small number division: So the final extra part that I'm gonna include in our controller is gain that you may or may not use, depending on your error. So what would be the game? So you see, right now you have a situation where you have your cube falling down, right? And so you have some kind off vertical position, which we denote with position. Why, Okay, so this is the height off the block. The other term that we have is the horizontal error. So it's how far away our train is from the block. And so far we've bean Onley working with this horizontal error. Even when you have this inclination, this angle 15 degrees. Still, we always measure horizontal error. But what I wanted to do, I wanted to introduce some kind off dependence off the height off the block and how far the strain is from the block. So what I'm doing here is I want to multiply my horizontal error, which we have here. I want to multiply by a gain. And that gain is the horizontal error divided by the vertical height. So why do I want to do that? And by the way, this is actually the absolute value off the vertical height. So when you have negative altitude, let's say when you have like minus 15 or something like that, then I take the absolute value of it. This number here it's always positive. But what I want to achieve is that let's say if the height of this block is, let's say 15 meters and the train is also 50 meters away from this reference line, then it would be 15 divided by 15. So it would be one. So I would multiply my e x, my error term by one and it wouldn't change. But suppose that I have a different situation. I have a very small height, Let's say two meters but I'm 10 meters away now. If I'm 10 meters away, then I would have 10 here. And so if position why is two meters 10 divide by two would be five Now This gain five I would multiplied by my X which Waas Ah, 10 right 10 times five would be 50. So I would amplify my error because I need to speed up the block almost touches the rails, right? The block is almost at the ground and I'm still far away. So when the block is very near to the ground, I need to speed up. I need to go to the right very fast in order to catch it. So when I'm very far away from the block and the block is very close to the ground, then I need to somehow increase my error. So what this gain allows me to do is that if I'm 10 meters away from the block and then the block is like, let's say, only two meters, then this gain will be greater than one would be 10 divided by two, which is five and then it will be 10 times five equals 50. So now I have greater error turn and that error term. I will then multiply by KP, which is the proportional part, and because of that, my proportional part will be stronger and I will have a stronger force that will push me faster towards the block. Okay, But now if I have another case, let's say I'm very close to the block. And so let's say I'm two meters away from the block, but the block itself is at the height of 10 meters, so in this case on two meters away too is here. But the highest 10 so two divided by 10 would be 0.2. So I would multiply to by 0.2 right. And now I have a smaller error. So my error would be 0.42 multiplied by 0.2. It would be 0.4. So the error that I have here will be smaller than the actual horizontal error and that smaller error I will then multiply by KP and I will have a weaker force. That means that the motion off this train will be slower. And that's exactly what I want, because the reasoning is that I'm already very close to the block. But the block is still at a quite high altitude, so I have more time. So that's why I don't need to go so fast. So this kind of gain well, let's say introduce some kind of connection between the horizontal error and the height off the block. However, there is a condition that I implemented. Okay, so, first of all, I didn't write it here, but again, I want to say it again. I said it once but I want to say it again. Suppose that your block falls down in the calculations in the coat, then your altitude becomes negative. You think that you would then divide this error term by a negative value. But that's not the case. In fact, both values are absolute values. So this e X no matter whether it's a positive error or negative error, I make it positive in my coat. So I take the absolute value of it, and I do the same with this altitude. So these values here are always positive because I don't care about the directions. I just care about the magnitude. If I'm close to my block right and the block is high in the sky, then I just want to go slower. If I far away from the block. But the block is almost at the ground. I want to go very fast. Now there is a condition that I applied, and that condition is that if my error is between my understand and 10 then I skip this game, then I just go around it. So in the code, it's an if statement if this condition is true and, uh, my error is greater than minus 10 and less than 10. Right? If I'm between my understand and 10 in that interval, then I skipped this game and e X equals e right. However, if it's not true, if my error is less than my understand or greater than 10. In other words, if this condition is false, then I go through this game and why do I do that? Or first of all, in my controller one tow. Avoid a situation where a divide by zero because once this block reaches the ground and five unable to catch this block and it reaches the ground, then I will have a zero here and then the cold will throw you an error because you know you can divide by zero. And the other problem is that C. It's quite dangerous, actually in real life to divide by very small numbers. Because what will happen if you have 0.1 meters here, right. If you divide a number by a super small number, then you will have an extremely big gain, right. So if you have an extremely big gain, then this error here will become very big. And so you're apply. Force will become astronomical, and then you will have some kind off huge force, and it will ruin your system, or it will give you an error. So that's why in order to be safe, I stay away from very small numbers when they're in the denominator. Because I don't want to divide by very small numbers. Because when you divide by very small numbers, you get very big numbers that can give you undesirable results. And also you want to avoid, ah, possibility where you divide by zero. So that's why I included this condition. And so this is the extra party now controller. Now we we put it all together, our p I D controller and then this extra part the controller where I play around with a gain then our entire controller looks like this. This is our entire controller. So you're a return enters here, checks the conditions. If the conditions are true, then I ignore this gain. I just go around this road here. If this condition is false, then I go through this gain. I modify the magnitude of my error and then this error is fed into the P i. D controller. It goes to the proportional derivative and interval controller that I can tune. And then the summation off. All that will give me the applied force that is produced by the magnets and apply to the train. And so that apply force that comes out here is then fed into your system into your train system. Remember, you have a mathematical model here, and then this apply force will then influence your exposition. And this entire loop happens every 0.2 seconds. So every 0.2 seconds, you have a new force new X value, new error. In this case on Lee, the the reference value here stays the same. So the reference value in our case is not changing as a function of time, but this position changes as a function of time. Apply force the error term. So your position goes here, checks it against the reference position. It calcalist the error. The error interview controller goes through all this and produces this apply force that is fed into your system. That apply force will influence the system to get your ex closer to your reference X so that your error would become zero eventually. So that is it. What I'm gonna do next, I'm gonna show you the simulation with the train, and it's gonna be the case where you have this angle. So I'm gonna run a couple of trials where we'll see how r p I D. Controller is able to catch the falling blocks. All right, see you there.
29. PID: Magnetic train simulation (inclination angle & PID): Okay, so now I'm going to show you the simulation of the most difficult case. The entire controller is working now and applied to our train. So I have five trials. The angle will be 30 degrees over six radians. So the inclination, the rails with respect to the horizontal line, it's going to be 30 degrees. And then k p is 300, K d is 250, KI is 50. So let's run it and see what's going to happen. So here is trying to catch it and it managed to do it. And if you pay attention to this window here, this is the integral of the error, right? And so it mister, so it's not very well tuned for this situation. So this is the error, window error as a function of time, the derivative of the error as a function of time, and the integral of the error as a function of time. And this is acceleration, this is velocity, and this is position here. Now, we didn't tune it so well. So let's see if we can tune it a little bit better. So what I'm gonna do, I'm gonna decrease the KI. I'm just gonna say it's ten, gonna make KD 300. And I'm going to leave KP 300. And let's see what's going to happen. So now the resistive effect from the derivative part is greater. So perhaps we are going to be able to catch all the cubes or maybe not. I am going to leave the code in this section that you can download it and you can play around with it as much as you want. And also the water tank code. You can also play around with that one. Ok, so this time we were lucky, so congrats, we did it. So thank you very much. And I hope you've learned a lot.
30. Intro to (Linux & macOS Terminal) & (Windows Command Prompt): Welcome back. This short video is for those who haven't really worked with Linux and MacOS Terminal or Windows command prompt. So if you're like me some years ago, who hasn't really encountered terminal or command prompt, then this video is for you. If you are familiar with terminal or command prompt, then please skip the video. This video is really for people who have almost never encountered Linux terminal or Windows command prompt. Macos Terminal, both the terminal in Linux and in Mac OS. And then the command prompt in Windows. They're very similar. And in this course, I recommend you to use terminal or command prompt to run Python files. And so I'm gonna give you a short explanation of how to use terminal or command prompt. For the purposes of this course, essentially, I want you to know how to launch Python programs using terminal or command prompt. So if you look at the screen, then you know that I'm in my desktop. And so now I'm gonna go into my default home folder. So you see that I'm in my default home folder and then I have a lot of files here. And now from this default home folder, I want to enter into my Desktop folder. And my Desktop folder is right here. So I'm going to click it. And you see, I have my files here. These files that you see here. These are these files here. So it's the same thing. And now let's say that I want to go back into my default home folder. So I'm gonna go here. Okay? This is, most people in the world use computers. However, there is another way to navigate through these folders. Here, I have my terminal and in Windows it would be command prompt. And in Mac OS, you also have terminal. And so I have opened my terminal. And actually here inside my terminal, I'm inside my home folder. So I can write here Ls. And that command will show me all the files that I have in my home folder. And there you go. You see I have all my files here. And by the way, if you are in Windows, then you don't write ls, you right, deal. But in Linux you write Ls. So being here is the same like being here. Now if I don't want to see those files anymore, then I'll just write clear. And now, just like we went from our default home folder into our Desktop folder. And then we went back to our Home folder. What we did, we navigated through folders, but we can also do it through the terminal. And we do it like this. Cd, and then we write desktop. And now what we have done, we have done this. We have entered into our desktop folder, but through our terminal. And by the way, in Windows and MacOS is the same thing. If you want to change your folder in Windows, you write CD. And the same thing applies to MacOS. And now if I want to see what I have inside my desktop and I write Ls. And you can see I have the same files here. So right now I'm in my Desktop folder, my screen, and also in my terminal. And now let's say that I want to enter my folder here. So you see I have more files here. And I can do the same thing in my terminal. I write CD, which is change directory, and then the name of the folder, MPC PID. And by the way, in terminal, you can complete the names of the folders or files with the tab button. So for example, I have only written this part and then I click the tab button. And it has autocomplete id, the name of the folder. And then I click enter, and I'm inside the folder. I write Ls. And as you can see, I'm now inside the folder called MPC PID. And you can see that the same files that I have here, the same folders, I also have them hear all of them. Of course, you need to have that specific folder in your current location only then you can enter into that folder through this cd command. If you don't have that folder in your current location, then you can do it. You can only enter into the folders you actually have in your current location in your computer. Just like when you're in your desktop, you cannot enter into the folders from your desktop that you do not have on your desktop. The same logic applies to terminal and Windows command prompt. If I want to go back, I write cd space two dots, enter, and then I'm back. And so again, if I want to go one folder pack, I can just write CD two dots. And guess where I'm at right now. Well, I went to folders back and now I'm again in my home folder. And so if you haven't really worked with terminal or command prompt before, then do like I do. When you write your Python script. Then just save it in your desktop. Just save it here. And so when you're in your desktop, then you can see that you're saved file is here. And so when you're in your home folder, in your terminal or command prompt, then just go into your desktop folder. Cd, Desktop. Again, CD is in Linux, Windows. And MacOS. Now when you are in your desktop, the new right, either ls in Linux or deer in Windows command prompt in Mac OS, it's also LS. And then you can see the files that you have in your desktop. So you have to Python files here, this one here, and this one here. And remember, Python files, they need to be saved with this dot py extension. And so when your file is in your desktop and you are inside your desktop, but through your terminal or Windows command prompt. Then in Linux terminal, you run your Python file like this. You write Python three. And then the name of the file, which in this case is this one. And then you press Enter. If you have an error there, then it will display you this error. For example, I have an error here in line 15. In that case, you have to enter into your Python file that you had saved in your desktop, which is this one here. And so on. Have a bunch of stuff that I haven't commented out. So I'm just going to delete it. So I'm going to save the file. This is the file that is saved here in desktop. And then I can close the file. And so I'm going to clear my terminal. But you can see that I'm still in my Desktop. And so in order to run the file, I write Python three. And then Calculus seems straight line, dot py and enter. And there you go. You see the Python file is running. If you want to close the file, you just press X. And that's how you run a Python file with your terminal. Now, if you have Windows command prompt, then it's a bit different. We'll in fact, the only difference is that in Windows command prompt, you don't write this. Once you are in your desktop, you simply write the name of the file. So this would be in Windows command prompt. This one is in Linux terminal and in Mac OS terminal. So in Linux terminal and MacOS Terminal, you have to write Python three and then space and the name of the Python file. And don't forget the dot py extension. In Windows Terminal, you simply write the name of the Python file with this dot py extension. And then you press Enter. And that's the only difference. And now if I want to print something, so let's say that I enter into this file again. And let's say that I want to print this distance array. Then I write here print distance, I save it, I close it. And then if I run my Python file again, then of course I cannot do it like this because I'm using Linux. In Windows Command Prompt, you would do it like this, but in Linux, I write it like this. And by the way, terminal remembers your previous commands. So let's say that you're in your desktop. And if you press the arrow up, then you get your previous commands. You press the arrow up again, and then you get the command before that. So with this command, I run my Python file. I have my animation here. And as you can see, I have printed my distance array. So if I make it bigger, there you go. This is your distance array. So we write clear. And by the way there many commands, both in Linux and MacOS, Terminal and Windows command prompt. You can copy paste files using terminal or command prompt. You can move files from one folder to another folder. Using terminal or command prompt. You can delete files and install programs using terminal and command prompt. And the thing is that if you get used to it and you do it many times, then you might be faster working in your terminal or command prompt. Then in the traditional way, where you would enter your folder and then either press control C, control V, if you want to copy, paste it, or click the right-click and then copy and then paste. And so it's a nice thing to learn to work with terminal or command prompt. And there are many good tutorials on YouTube that I have used to learn about it. So let's say that I want to enter into my MPCP Aid course folder again. So I'm here now you already know how to go back, write cd and then space and two dots. However, what happens if I don't put those two dots? If I only put CD, then no matter in which folder you are, you go back into your default home folder. And so that's it on the terminal end, the command prompt. Thank you very much.
31. Python installation instructions - Ubuntu: Welcome back. In this video, I would like to show you how to install Python and the necessary libraries in order for you to be able to run the simulations in Python are first start with Linux, Ubuntu. And then in the next video, I'm going to do it in Windows. At the time of this recording. The Python version that you should install is Python 3.8.5. The newest out there is 3.9. However, I've checked that and the libraries such as numpy and matplotlib, they don't work well with Python 3.9 yet. I guess it's two new, perhaps they will later, but not at the time of this recording. So you should have Python 3.8.5. If you have Ubuntu 20.04, like I have it here, then Python 3.8.5 should come by default along with num pi. You can check the version in terminal like this, Python three and then two dashes and then version. So you see I have python 3.8.5 and you can check the version of Numpy like this, python three dash C. Then you put here a quotation mark, import, numpy, semicolon print. And then you're going to put here Num Py dot. Then you have to underlines here. And then you're gonna put version, then another two underlines, and then another quotation mark here. So here I have num pi 1.17.4. That's what I received by default. These two things I received by default when I installed my Ubuntu 20.04. If you don't have Python 3.8, then you can install it with these commands, sudo opt update. And you put your password here. So it will give you some upgrades. And then you will write sudo, which is superuser. Then OPT install software, dash properties, dash common. Then I'm going to write pseudo, add, dash, APT repository, PPA, colon, dead snakes than slash and PPA. So I'm going to press Enter and then I'm gonna write pseudo OPT and then update the pseudo APT. Install Python 3.8, not 3.93.8. And then to check the version, you write Python three dash, dash version. And then if you don't have num pi, you can add it like this. Pseudo APT install bison three dash NumPy. And so to check the version, you will have Python three, dash c, then quotation mark, import, numpy, print, parenthesis, num pi dot, then 200 lines, version 200 lines. And then you will have a quotation mark here. So that's your NumPy version here. And now you have to get the matplotlib library as well. At the time of this recording, the newest version is matplotlib 3.3.3. However, if you want to run all my simulations, then I recommend you to install matplotlib 3.2.2. You can do it with these commands. Sudo APT update. Then sudo APT install Python three dash PIP. Pip is a Python package installer. So you check the version of your PIP. So PIP for Python three would be PIP3, then dash, dash, and then version. So here it is. And now you write PIP3 install matplotlib. And now if I press Enter now then I should be able to get matplotlib 3.3.3. However, I want to get matplotlib 3.2.2. So I'm gonna put here two equal signs and then 3.2.2. And if you already have matplotlib 3.3.3, then this latest command will uninstall it automatically and replace it with 3.2.2. And now you can run the code, but this is very important. You have to run it in Linux terminal or Windows command prompt. Do not use IDEs like spider or Jupiter notebook. The animation does not want to work well in there. The most robust way is to run it from terminal or from Windows command prompt. So I have a file here, calculus sim, PID, train dot py, and I want to run it. So in my terminal I will go to my desktop. So change directory or CD Desktop enter. I can see all my stuff here with an ls command. And so in order to run this file, I'm going to write Python three and then Calculus sim PID trained at pi. And there you go, it works. So that has been in Linux. And now let's see how to do this in Windows.
32. Python installation instructions - Windows 10: Welcome back. So let us now try to install Python and its libraries for Windows. So this is the Python website here. The newest version is 3.9. However, the problem might be that at the time of this recording, the numpy and matplotlib libraries might not be ready for this version. So in order to run the simulations, we're going to take an earlier release, Python 3.8. And so here you have Python 3.8.6 at the time of this recording. So if you have a 64-bit machine, then you need to choose a 64 bit one. And if you have 32-bits, then you choose the 32 bit options. So we're going to choose the 64 bit web-based installer. And now we're going to open the file. What we're gonna do now we're going to add Python 3.8 to pass. I think it's important so that you could run your Python codes from whatever place in your computer. And now let's customize the installation. I personally don't need that documentation file, but you can leave it if you want. The next. Then we're gonna put here install for all users. And now, do you want to allow this app to make change to your device? Yes. And it's installing. And so we have finished installing Python and we're going to close it now. And so now we have our Python and let's check if it works. In our case, we will need to launch our programs from command prompt. So I want to test it from command prompt. The animation does not want to work well in IDEs like spider or Jupiter notebook. The most robust way is to run it from terminal or from Windows command prompt. So I've opened a notepad and let's see if I can write a program here. So I'm going to write here print and then hello world. And now I'm just going to save this somewhere. And I'm gonna save it like this. Hello dot py. So here I'm going to put all files and hello.py. And there you go. Now I want my command prompt. Here it is. So now I need to find my way to desktop. So cd Desktop. Now I'm here. Ls. Well, LS is not working because it's a Ubuntu thing. But I think in Windows it's dear. And you see you have your hello dot pi here. So can we run it? We can. And so it works. Ok, but to run our simulations, we need a couple of libraries. We need numpy and we need matplotlib. When we installed our Python, then you can see that our PIP here was also included or PIP. So that's Python package installer. And in order to install numpy, we need to make sure that this PIP is the newest one. So we're going to write here Python dash M, PIP install, dash, dash, upgrade PIP. Ok, so it now says successfully installed PIP 20.3. And now let's install Numpy. I'm gonna write PIP install Numpy. Then two equals signs 1.19.3, and now I have NumPy 1.19.3. Now let's check if it works. I'm going to read here Python. And then I'm going to write here Import num pi. It didn't give me an error, which is very good. So this is our code here. Import numpy as np, and then I'm going to write here print np dot pi. So the pi value. And so now I'm going to write exit. And then I'm going to run this hello.py file and it gives me my PI value. So that's very good because it means that we also have working Numpy here. And now we need to install matplotlib. I would recommend you to install the matplotlib version 3.2.2. At the time of this recording, the newest version is matplotlib 3.3.3. However, if you want to run all my simulations, then I recommend you to install matplotlib 3.2.2. So I'm going to write here PIP install, and then matplotlib. Now if I run it now then I will most probably get the newest version, 3.3.3. But since I want to get 3.2.2, then I will put here two equal signs and then 3 to point two. Ok, so it says that successfully installed. So I have here this calculus seem PID train, and let's run it here. So calculus seem PID train and it works. Now, it's a little bit slow here, but that's because I'm running my Windows ten on a virtual machine. At the moment I am Linux user, so I use Ubuntu. And so in order to make this demonstration, I downloaded the VirtualBox machine. And that's why the simulation is a little bit slow. I'm sure it's going to be faster on your Windows machine.
33. Python installation instructions - macOS: Welcome back. So let's now install Python and its libraries for MacOS. And we're going to use the latest version, which is big. Sure. Let's start with going to the Python website. And now we're gonna go to downloads, all releases. And I would not like to download Python 3.9 because I wanna make sure that all the other libraries that are, I'm going to be using, that they are fully ready for that version. And so all my tests have been successful with Python 3.8.7. And so we're gonna go to Mac OS n. We're going to download the Mac OS 64-bit Intel installer for Python 3.8.7. Do you want to allow downloads on www.python.org? And of course allow. And so I'm gonna go to the Downloads folder. So here's the installer that I'm going to click on. And so now I have this text. I'm going to click continue. I'm going to read everything. Again. I'm going to click continue. And of course I'm going to read everything. Continue, agree, install. And then here I have to put my system password with which you login into your system. And so it will start installing Python. And so at some point, we'll have this folder here with these files. And I can just ignore this folder. And here you can see that congratulations. Python 3.8.7 for Mac OS is successfully installed. And now we don't need the installer anymore, so we move it to trash. We can close this folder and we can close this website as well. And now let's test if our Python is installed correctly. I'm going to use terminal in order to launch my Python programs. I would recommend you to do the same. I would not recommend you to use IDEs such as spider or Jupiter notebook. The animations might not work if you launch your programs from there, the most robust way is to launch them from terminal. And now let's go into our desktop folder. Cd. Desktop. Cd stands for change directory. So I have a Python file here, test dot pi. And I'm going to open it with the idol. I'm going to ignore the shell and I'm going to go where the program is written. Now, I don't care about the numpy nor pillow right now. I just want to know if my Python is working properly. For that. I'm just gonna write here, print hello world, and then exit. That will end the program at that point. And so if I close this file, then it's going to ask me if I want to save it. And I'm gonna say yes. I'm going to close shell as well. And then here, when I'm in my Desktop folder, in my terminal, I'm going to write Python three. And then the name of the file test dot pi. And as you can see, it prints hello world. So our Python is working very good. But now if I go back to our program and then I delete all this stuff and leave the original program. If I save it now and close the shell and run the program now, then I will get an error because I don't have a numpy library in your terminal, right, CD, so that you would get out of your desktop folder and be in your default home folder again. Before we can install num pi though, we have to install Pip. Pip is a Python package management system. For that, we go to Safari and then we're going to go to this website, Pip dot pi, pi, so p y p a dot io. Here we go to installation. We're going to make sure that we have unix or MacOS here, not Windows. And then we're going to come here where you have installing with get dash, Pip dot pi. And then we're going to copy this line. And we're gonna paste it into our terminal here and press enter. And then you have to go back to the website and copy this link as well. And then you can paste it here in your terminal end before you press Enter, you have to put here Python three. So a small modification. And then you press Enter, and now it started installing it. And now you have successfully installed the Python package management system, PIP. And now you can write pip install num pi two equals signs 1.19.3. And now you have successfully installed NumPy 1.1.3. And now you can write cd Desktop. Now you enter into your desktop folder. Now before we run our file, Let's enter into our file again through idle. At this point, we don't care about the Pillow library. That's the library that you need when you work with images. At this point, we're going to ignore it. We just want to test NumPy. And so we're going to write here print np dot pi, and then we're going to write here exit. And so if our Numpy works, then we should get a PI value. So when we close it, then it asks us to save it. We're going to click yes. We're going to close the shell. And we're going to write Python three and then test.py.py. And as you can see, we get our PI value. And that means that our NumPy library works in your terminal, right? Cd, so that you would get out of your desktop folder and be in your default home folder again. And now we have to install Matplotlib. For that, we write pip install matplotlib two equals signs and then 3.2.2. In order to avoid any kind of complications, I would ask you to install matplotlib 3.2.2 and not 3.3 series. And so we have successfully installed our matplotlib. And now we write cd Desktop because our Python file is in the desktop. And so if we run an animation file here that requires matplotlib, then you can see that the animation is working. Of course, it's very slow. But that's because I'm using VirtualBox and that's it. Now you have all the necessary libraries in case you use the mac system as well. So I'll see you in the next video. Thank you very much.
34. PID train code explanation 1: Welcome back. In this video, I will explain to you the code for the PID train. So let's go through it together. The first thing that I'm gonna do, I'm gonna import all the necessary libraries that I need. I need num pi, I need matplotlib. I also need this random library because I want my cubes to appear randomly on the screen. So it has appeared here, and now it has appeared here. And so there is a random function that will take care of that. And then we define some inputs. First of all, we have trials. Here you decide how many times the train needs to catch the cube. So if I put two here, then the train needs to catch one cube and then another cube. And then the animation will be over. If I put here 20, then there will be 20 different cubes sequentially. You catch one of them, then you can show number one, etc, up until 20. Then here you have your inclination angle. So I have here pi over six, so that's 30 degrees. So that will give you this kind of inclination. But if I want to make it 0, then I can just multiply this angle by 0. And then my inclination angle will be 0. And there you go. No more inclination angle. Then this g value is the gravitational acceleration on Earth. This is the mass of the train. And here you have your three PID constants, the proportional one, the derivative one, and then the integral one. In this variable, trials global I store how many trials I have. And the reason why I do that is because this variable trials, it will decrease by one in each trial. And I will need that in the future in my simulation loops in order to know which trial loop I'm at, at that moment. But this variable is stays constant. And I will need it later in order to create the amount of frames for the animation. Then here what you see is a function. The function is called set x ref. It takes in the inclination angle and it gives you a random horizontal and vertical position. So at some point in the code, in fact, it's right here. Here I enter into this function. The purpose of this function is to give me a random position for the cube for each trial. So this is a random horizontal position. The function here is random dot uniform. And then I have two numbers here, 0120. It means give me a number. Between 0120 using this uniform probability distribution. As you know, you can also have a Gaussian distribution. So if this was 0 and this was 120, then in most cases, I would get my cube somewhere in the middle. But a uniform distribution. It will give you and equal probability for the entire range. And the reason why I have 0120 here is because here on the horizontal axis, I go from 0 to 120. So I want my cube to appear horizontally randomly. But then I also want a random vertical position. But here I have to do it differently. I want to tie it up to my inclination angle. Essentially, if this is my rail here, and so here I have 0, and then here I have 120. Then I define some kind of region in the vertical direction where this cube could randomly appear. And then of course, if I combine it with a horizontal region where I used uniform probability distribution from 0 to 120. That means that my cube will appear randomly somewhere in this area inside this rectangle. But what if I increase my inclination angle? And now my rail goes like this. And so my cube appears randomly here. Then obviously I will not be able to catch it, right? So what I want to do, I want to tie this vertical distance to this point here. So let's say that if my inclination angle is 0, and then I say that, okay, vertically, Give me a cube in between 2040 meters. So this distance here is 20 meters. But if I have some kind of inclination angle here, then it would be like this. Give me a cube vertically in this region. So now the distance here would be 20 and the distance here would be 40, like this. And so my cube will appear somewhere in this region. So you see, I tie this vertical distance to the corner of this rail because this is my initial position. That's where I always start from. And so to achieve that, I do it here. Here I have 20 plus 120 times tangent of the inclination angle. If this is my inclination angle. This horizontal distance is 120. Then 120 times tangent alpha will give you this distance here. That's your 120 times tangent alpha. And then I add 20 here. So I'm here. And in reality, I also add plus 6.5 dance because this card here that I have, it's actually shifted up by 6.5 meters. So in reality, to be more precise, the 20 meters goes from this point here up until this point here. So that's actually your 20 meters. So I connect this region to this point here. But from this point to this point, it's actually 20 plus 6.5. And then here you have another point. And that's actually 40 plus 6.5. Because 40 would be from here. From this point to this point, that would be 40. And that's what I'm doing here. And so I get my random x and y position and then I return it. Next, I defined my time interval, 0.02 seconds. Then the beginning of time is 0 seconds. The end of time is five seconds. And here I create my time array. I say that I go from 0 seconds to five plus d t seconds. So in here I have 5.0.2. Why? Because in Python this number is included, but this number is not included. So if I get here five, then my array will be like this up until 4.98. And that's because the last number here is not included. That's if I only had my tea and but if I have my t and plus d t, then I will have here 5.02, which is not included, but my five will be included. And then this DT is just the interval. It's this 1.020 seconds. And so I create my timer re. Next, I have to define my force of gravity, which is minus mass times g. So the force of gravity points down. Next, you see that I'm defining a lot of 0 arrays here. When you simulate, then you have to deal with arrays. And there are several ways you can do it. You can start with an empty array and then you can just put your data in and then overtime, grow your array. That would make your program very slow. If you already know in advance how big your time array. Or maybe x-ray or y array will be. And you should know it because you have your time array. That means that for each time value, there will be some kind of value for x, for y, for velocities, for accelerations. For all these variables, there will be some kind of value for time equals 0, for time equals 0.02 seconds, et cetera. So you already know how big these arrays will be in which you are going to be storing all your data. In that case, it is much better to define a 0 array with the right sizes. You predefine an array that has the same size like this time array. The only difference is that at the beginning you only have zeros there. And then as you go through your simulation loops, where needed, you replace your 0 with some kind of number, whatever it is. And that kind of programming is much faster. And where possible, you should do it like this. Otherwise, if you start just growing your vectors and matrices, then it will become very computationally heavy. And that's what I'm doing here. I'm redefining my arrays. For example, I have here displacement rail. Well that's this distance from here up until whatever point along this rail. And of course, if my inclination angle is 0, then my displacement rail would simply be my horizontal displacement. But if I have an inclination angle, then it goes along the rails. And so for each time value, I will have some kind of value here. But at the beginning, I define it as a 0 array. And you can see that it has two dimensions. It has trials, and then it has length time. Why do I do that like that? Well, that's because remember, I have more than one trial. So my displacement rail array, just like all other arrays in the simulation, they will have her trial one, trial to trial three. And then here in the column, you would have your time. This would be your time dimension up until the very end. And so when you have your animation and first of all simulation and then animate the data. Then you see that once the first trial finishes, then the second trial starts. Alright? And so let's see if it catches it. Very good. So what just happened was that we first went through the first trial through time, and then we went through the second trial through time. And then if I have more trials, then I will have more rows here. And I do that for displacement rail. I do that for the velocity of the rail. I want to know how fast I go in this direction or in that direction. I also want my acceleration vector in this direction or in that direction like this. That's here. Then I have these position x train and position y train arrays. All that really means is that I decompose this displacement rail into two-dimensions. So if this is my displacement along the rail, will then this will be my exposition and this will be my y position. Then I also need an array for my error, error dot and error integral. I need all these values to be stored somewhere. Because when the time comes, I take those errors and e dots and eats out of these arrays. And then I multiply them by my PID constants. Then these two arrays, therefore the cube. But you see they all have the same sizes. They all have the number of trials as rows and time lengths as columns, because you have a value for each time element. And then since you have multiple trials, then the total amount of elements that you have is the amount of trials times the amount of elements that you have in your time array. Here you have your x and y position values for your cube. That's where you store them. Here, I decompose my gravity vector, and I only obtain the tangential component. I don't need the normal component of my gravity vector. And the reason is very simple. If this is my force of gravity, and then I decompose it like this. This is my force of gravity normal, and this is my force of gravity tangential. And this is the inclination angle that I also have here. Then this normal component will be automatically canceled by this normal force here. Just like when you stand on the ground, you don't accelerate downwards. Why? Because your force of gravity is equal to the normal force like this. In this case, however, the normal force that you have is equal in magnitude and opposite in direction to the normal component of your gravity force. So they cancel out. The net result will be 0. So the only component that really matters is this tangential component. In fact, if you don't apply any other forces and we neglect the friction force and then the air resistance force, in other words, the drag force. Then this tangential component will make this train slide down. That's why I only extract this component, the tangential one, and I forget about the normal components. To extract this tangential component, you multiply your gravity force times sine alpha. And that will give you your tangential component for the force of gravity. And that's what I do here. Then I have to define my initial position in the x in y dimension. Essentially I'm saying that start from here. And here this is my initial displacement rail. So my initial displacement rail value is this distance. And in order to get this distance, It's just the Pythagorean theorem, right? You take the horizontal component, which is 120, then you take your vertical component. Let's put y, and let's just say that the horizontal component is x. So to get this distance, it's very simply x squared plus y squared and then square root. And that's what I'm doing here. And then I say that my initial velocity along the rail and my initial acceleration along the rail, they are 0 meters per second, 0 meters per second squared respectively. And then here, I take my initial position in the x dimension in DIA, sign it to another variable, because this variable will be changing. But I need this very initial variable later on for the animation purposes. And I need these variables to keep track of my trials. Whether I'm in my trial one or two or three. And now this is where the simulation starts.
35. PID train code explanation 2: Because of the fact that I have more than one trial. I have trial one, trial to trial three, et cetera. You can expect that I have two loops, one loop inside another loop. So loop one is to run the trials and then the inner loop. That's to run my simulation through time per each trial. And that's exactly what I have here. My outer loop will be Weill, and then this would be my inner loop that simulates my simulation through time. You can see that while trials is bigger than 0, run this loop. What does it mean? While if at the beginning I say that my trials is two, and let's say that it's five. If my trials is five, then five is greater than 0. Then I enter into this loop. Then my inner loop starts. That simulates one trial through time. My inner loop finishes here. And then I have some stuff in the outer loop in the end as well. And in the very last row, I have trials equals trials minus1. It means that if my trials has been five so far, then now it will be four. So four is still greater than 0. So i run it again. Then it becomes three. I run it again to, i run it again one, or run it again. And then it will be 00 is not greater than 0. Therefore, this becomes false. And I do not run this loop again. Now when I enter into my loop at the very beginning, then here I take my random x and y positions for my cube. This here simply means that if my trials at the beginning is five, and then I had assigned this variable to this variable right here. Then five minus five would be 0. So it would be my zeros time. Remember in Python you should start counting from 0, not from one. Usually we count from one. But the thing with Python is dead when you have some kind of array. And let's say that you have three elements here, 567. If you want to get this five, then you have to write t and then bracket 0, not one but 0. Then you will get this one. T1 would give you this one. And then t bracket two. It will give you this one. In MATLAB. It's different. In Matlab. You will put one here, two here, and three here. But in Python, you can from 0, then one and then two. So this would be here, 0, rho 12, and then in terms of columns. 0123. And then later when my trials is four, then five minus four would give me one. Then when my files is three, then five minus three will give me two. So that will tell me that I'm in this outer loop already for the third time. 012, it means for the third time. And then here, I give x and y array values for my cube. My x value will not change. You see my cube only changes in terms of y. And when you have a new cube, then again, it only changes in terms of why it doesn't move diagonally. So my x stays the same. And then my y value, well that's just the initial y value minus this gravitational acceleration divided by two times time squared. Well, that equation just comes from physics. So it's your initial position minus 1.5 times g times t squared. And of course here I assume that my initial velocity is 0. So the distance covered in the vertical direction would follow this rule. Then we'll look at these variables a little bit later. And now we start with our inner loop. We start simulating through time per each trial. At the very beginning, when my i equals one, I assign my initial values for displacements, then velocities, accelerations to these predefined 0 raise that I had defined right here. So you see times. And that's why I needed this one here. Because at the very beginning, when my trials was 510, trials magnitude was also five, then times was 0. So I had 0 here. That means that I said that I want to be in this row, the 0 row. Then in the second trial, my trials is 45 minus four is one. And then I will have one here. So I will have this row here. And then here I give you the position of the column. So the very first column, 0 column here I sign my initial displacement position in the x and y direction, the velocity and then acceleration values. That's at the very beginning. I didn't do that when my i is greater than one. I just need to do it at the beginning. Then I compute my horizontal error, the exposition of the cube minus the exposition of the train. Notice I'm using the exposition of the train, not the displacement value, but the exposition of the train. So if my cube is here, then what I want is this horizontal position, that would be my error. Then if you remember, I modified this error by also. Computing this vertical distance. And we can call this one x and then this one e y error in the y direction. And so at some point I had this equation, error x times the absolute value of error x over the absolute value of error y. So let's say that if my error x and error y were equal, then this ratio would be one, and then my horizontal error would not have been affected. But if, for example, my horizontal error is much bigger relative to my vertical error, then that would increase my so-called error. And then I would go faster in this direction. In this case, I would go faster along this rail. Another way to think about it is that if this denominator is small, then that means that this cube is very close to the ground. I'm about to miss this cube. So that's when this value is very small. But a very small value in the denominator would increase this ratio. So my total error will be greater. And so my proportional part in the PID controller would be more powerful. If however, this denominator is great. That means that my cube has high altitude, and so I still have time to catch it. So in that case, this value would become bigger, but the entire ratio because of that would be smaller. So my total error would be smaller. And my proportional part in the PID controller would be less powerful. There would have been less urgency. Let's put it this way. I still have time to catch it because this error is big. The cube is still somewhere here. But then we discussed that when this denominator becomes very small and it becomes very close to 0, like 0.0.0, 01, then your total error could become very big. And then your system will behave chaotically. And so we put some kind of limits to it. And that's why I have this conditional statement here. This is when this position y of the cube or this y error, if it's greater than minus ten, smaller than ten. In other words, if this value ranges between minus 1010 and here you have 0. If you range here, then skip that part. Let it just be one, and then only take this part. And that's what I do here. But if I'm out of this region, then apply this condition. And so in this case, I would be here. And then here I compute the time derivatives of my errors for my derivative part in my PID controller, but not in the first inner loop. Why? Because in order to compute my error derivative and not only error derivative, also my error integral. So in this block, I do both. I compute my error derivative and the integral of my error over time. But in order to do that, I need error values from two samples before. So you can see from these indices here that if I enter into this block in the first iteration, then I will have an index error. Then, for example, when I have one minus two, I will have minus one, which in fact would not give me an index error. Because in Python, if you have minus1 here, then that means the last element of the array. So it will probably not give you an error, but it will give you wrong values. Instead of values from the beginning. It will give you values from the end. But then in other programming languages, it would give you an index error because you would be asking and elements from an array from the position that does not exist in this array. And the reason why I use indices i minus1 for the errors and error dots in then error integrals is because later on, when I compute my applied force with my PID controller and then compute the net force, where I add my applied force to the tangential component of my gravity force. And then when I take this net force and divide it by the mass of the train, then this i index is used for acceleration along the rail, for the velocity along the rail, displacement, position x and position y. And then here in this block, I want to enter here in my last iteration inside my inner loop. Because remember, I first defined all these arrays as 0 raise. But naturally, because of the fact that I have indices i minus1 here, i will never reach the last array element here. But I don't want the last array elements in these arrays to be zeroes. So I just take the penultimate values, the values from one sample time before. And then I put them into the last elements of my arrays. And so once I have my errors, error dots, and then error integrals, then I can take my KP, K d and K i values and compute my apply force. Then you know that the tangential component of the gravity force is always in this direction. It never changes. But then the applied force can be either in this direction or it can be in that direction. And depending on that, you will either have a huge net force in this direction or smaller net force in that direction. You just add the tangential force of gravity to your applied force. And then you will get your force vector that goes along the rails. You divide it by the mass, and then you get the acceleration vector along the rails. Then here, in order to get the velocity vector along the rails are performed this trapezoidal integration. In order to get the displacement along the rails. I again perform the trapezoidal integration. But now with velocities before it was with accelerations. Now it's with velocities like this. And then to obtain values for my position x and position y is just simple trigonometry. I take the displacement value along the rails times cosine. So that will give me this one here. If I take this red vector times cosine alpha, I will get my position x. And then if you have this red vector times sine alpha, then you will get your position y. And that's what I do here.
36. PID train code explanation 3: Now of course, you can see that once the train catches the cube, the Cube moves with the train. Like here you see, now the Cube moves with the train. To achieve that. I do it here. And let's see how I do it. You can see that I have two if statements here. Last for now, forget about this one. And let's focus on this line here. Essentially with this first line, I'm saying if this is my train, and let's say that I have some kind of central line, and this is my x position. So imagine that I have my cube here. And so you have your first condition. If position x of the train minus five is less than position x cube plus three, then this part of the conditional statement is true. So this would be from position x and this would be position x minus five. Then this would be position x cube. And this will be position x cube plus three, right? Because our convention is that x is positive in this direction. So here I have this sign here. So this value needs to be less than this value, which means that this wall needs to be more to the left. Then this red wall, this blue wall needs to be more to the left. Then you can see that indeed you can catch the cube. The second conditional statements says position x of the train plus five needs to be greater than position x cube minus three. Well, this is position x of the train plus five. And let's now assume that our cube is here. So this is position x cube minus three, this side here. So if this blue side is greater than this red side, then the condition is also true. And so I have an end statement here which means that both of these conditions must be true. And they are. If my cube is here, then this blue wall on the right is definitely greater than this red wall here. What I have to worry about is this edge here and then this edge here. The same logic applies to the other side. So that's how I check if I'm able to catch this cube horizontally. But I also have to take care of the vertical part. What if this condition is true? But my cube is somewhere here. Well then it's too late, right? Or maybe my cube is somewhere here, then is to early. And so for that, I have this second if statement. And here I essentially say this lower side of the cube and this upper side of the cube, they have to be in some kind of threshold. So I define two thresholds here. Like this. If my cube is inside this threshold, then it's true. If at least one edge, let's say the upper edge is out of this region, then the condition is false. These numbers here, they are obtained through trial and error. Because in this section, I didn't really think about the dimensions of this train or the dimensions of this cube. Actually, when I run my simulation, then to me what really matters is the central point here and that's for the train. And then this would be the center point of the cube. And then here as well. And so from Python point of view, these are just lines with some kind of width. And then I gave them some kind of width. And so these lines are wider. But there is no exact science between these kind of dimensions here. So all these numbers here I obtained through trial and error. When the animation was good enough. Then I kept these values. But the PID controller only works with these center points. The PID controller does not care about these dimensions here. So for the PID controller, the error between the strain and this cube would be this one. You would take one central point and then you would measure the distance to another centre point. But in order to make it visually appealing, I wanted to create an animation using Python animation tools. And then I had to do some trial and error with these dimensions. But that's essentially the logic. I defined some kind of channel here. And if my entire cube fits into this channel, then the condition is true. Then actually that means that I have caught my cube. So remember there are two conditions. One was for checking the horizontal distances where I worked with these edges. That was this condition. And the second condition, that's when I check if my cube fits into this channel that is fixed to the train. So the train goes down, then this green channel would go with the train. And so when both of these conditions for the horizontal and vertical motion are satisfied, then I enter into this loop and then I make my wind true. At the very beginning. My wind is false. It means that I haven't caught my cube. Then once I catch my cube, I say that when equals true. Why? Because the next time I run my inner iteration, i don't want to check all these conditions again. I already know that I have caught my cube. And I know that because of this wind variable, which is true and this one as well. So if when equals true, then that means that I had already caught my cube. Then here you can see that since I have caught my cube. Then whatever values I have in the arrays for my cubes, for the x and y position, I override them with the values that I have in my arrays for the train that will make the cube move like the train. So it will stop falling. It will simply move along. You see? Ok. And then the reason of this block is that if I don't have this block, then I will not be able to compute this one. I call this one change. Then I know that this cube needs to stop here. If I don't have this change, then my cube will magically appear here because the central lines of these two objects would align with each other. So I have taken away the change. And now look what's going to happen. You see the cube and then the train. Their center points simply aligned with each other. It's better to see with an inclination angle. You're about to see it now you see, and there you go. And you will see it again. And as you can see, the two central lines would align with each other. And that's why I compute this change. And then I have to put here minus n, then this change. And then this is in order to keep that cube together with a train in the y direction. And again, this number here is through trial and error. And that's the end of the inner simulation. Now you can see that once the cube is caught, then when the new trial starts, you don't start from the beginning. You start from your last position. And that happens thanks to this block here. Because here what I do, I take the last values from these arrays for my current trial. And then this would be the last column. And these last values for this trial for all these arrays will be assigned as initial values for all these variables for the next trial. So for this trial, I take my last velocity value, I make it the initial velocity value. I decrease my trials number. That's the end of the outer loop. And then I go back up and then I start with my new outer loop with my new trial. I get my random x and y positions for my cube. And then I again create arrays for my cube in the x and y direction and make my when false. And then once I start with my inner loop, the very first iteration, I assign my initial velocity as the first value for this velocity array. But for the new trial. But this initial velocity value, it got updated before here. The initial velocity value for the new trial is the last value of the old trial. And that's how I make sure that when the new trial starts, then might train doesn't start from the beginning. And finally, this delta. Well that's for this block here, that's to compute this change. Once I've caught my cube, then I don't have to compute the change again. So I make my delta 0, then I don't enter into this block again. But then when I start my outer loop again, I make my delta one again, because now there is a new cube that I need to catch. That's the end of the simulation. This is where the simulation ends. This is where all the data generation ends. The rest is just Python animation. All this is just to create those animations with Python animation tools. The main function responsible for Python animations is this one here, func animation.
37. Basic intro to Python animations tools: Now Python animation. It's a topic in itself, and it requires a separate course to really explain to you all the different nuances here. Nevertheless, I'm gonna give you a quick overview of the general idea of Python animations. Remember, animations is not simulation. Simulation is what we did here. Here we computed all our data. Here we applied our PID controller. Here we computed our positions, velocities, accelerations. Essentially we generated our data here. That's simulation. Now since we have all this data, the question is, how we are going to present it to other people? We can either plot it or we can animate it. And of course, animations look cooler. And in Python you have certain tools to do that. In the library called matplotlib. You have a function that we usually put in the end of the animation, which is right here, func animation. One of the arguments is Fig. That's the name of the figure that you use for animation. This figure here, it's called fig. And you define this figure called fig right here. You see, here you give it a size, resolution, dots per inch color. And here you have GridSpec. Gridspec four comma three means that if this is your figure here, then you have chopped it like this into these equal rectangles. And with these grids, you determine where you are subplots will be and how big they will be. For example, this big subplot here, it occupies these rectangles. That's this big subplot. You have one subplot here, one subplot here, also one here, here, also here. And here. As you can see, you have here subplot than q one. Also you have one here, and then here as well. So in total, this figure is divided into four by three rectangles, four rows and three columns. And so the way you assign those subplots to those positions is like this. Subplots. They also have names. For example, I call the big subplot AX Maine. This big subplot, its name is AX underscore main. And then I write Fig, which means that I'm talking about this figure here. Then dot and then a function called add subplot. And then here gs, which is the name of this action here. This gs tells Python that, okay, this figure has been chopped like this. And out of these rectangles, take 012 rows and then 01 columns. And that's how you get your Big subplot. And then these functions here, they are there to design your axis. So here I say that my x values range from 0 to 120 in the x-direction. And I also want my y dimension to be that big. Essentially. I want to go here from 0 to 120 and also from 0 to 122 here. And then x ticks, they essentially determine the intervals of these numbers here. And so if we go back to our animation function, that's our figure with all these properties. Then this update plot, it's a name of another function. And it's the function where you can design your animation. So if you go up, then this optic plot function, it starts from here. So this function is continuously called. And now this num variable is very important. Every time you call this function, this numb increases by one. So at the beginning you're num is 0, then it's 1234. The total amount of times that this function is called is determined by this frame amount. As you know, a video contains a frames. It's like having a lot of pictures that you change very fast and then you see it as a movie. So you need to define your frame amount. And then if you go down, then you put your frame amount here. Then here you have interval, which means that you are changing your frames every 20 milliseconds. Here you can write if you want to repeat your animation or not when it finishes. And this option, make sure animation smoother. It optimizes the pixels that it draws on your figure. And then of course, you need this function in order to see all that on your screen. And so the way animation in general works is that you need to think in terms of objects. So let's, for example, take this blue line, the horizontal error, this horizontal error, this line, this blue line, it's an object like everything else that you see here. It's an object you see in that object needs to be created somewhere. And I created here, I call it E F. Now it's also very important that you put a comma here. That's a python thing. If you don't put a comma here, then you will get an error. But the name of this object of that blue line that you saw, it's called E and F. We give it a color, blue. We give it a line width which is two. And these two empty arrays. They are reserved for x and y values. And then here you say that this object e underscore F is in this subplot. This subplot is also an object and it has a name. It's this one here. This is your subplot. You call it a x h. And then in this subplot, x one h, you create an object that you call E f. Then this function here, FuncAnimation calls this other function, update plot. And so you're inside your function. And then here you see that this is your E, f. Then you put dot set data and look what's happening here. Essentially, you're starting to extract something from 0 up until some kind of value. And this value depends on num. And remember every time this function is called, numb increases by one. I'm going to give you a simpler example. Say that this is our time array, and it looks like this. Now what happens if I write T bracket and then 0 colon and numb at the beginning, num equals 0. So what you have is this 0 colon 00 column 0 will give you an empty array. So you will not extract anything from this time array. Then the next time this update plot function is called from this function func animation. Then your num variable becomes one. In that case, you have 0 column one. So you will have 0 here because Python will extract this one, but it will neglect one. In other words, here, you will have t bracket 0. In other words, you will extract this element. Then that update plot function is called again. And your numb becomes 20 colon two would give you an array 01. So instead of this, you will extract this, and then you also extract this. So you will extract two numbers. Then numb becomes three. You go from 0 colon three. Then you will end up with an array 012. Then this t bracket 0 column num. It will extract three numbers, and then it will extract for numbers. So every time it extracts more and more numbers until you reach the very end of your array. And it does the same thing with your error array. C, you have error one, error two, error three, et cetera. If you extract one value for time, you will extract one value for error. If you extract two values for time, you will extract two values for error, three values for time, three values for error. And that's why in the animation, what really happens is that if this is your time axis and this is your error axis, then in the first frame, your object e and f, that we have here, and that we had defined in the past. Here. In the very first frame, there would be nothing emptiness. In the second frame, you would see a point. In the third frame, you will see two points. In other words, you will see a short line. Python will now show you points. It will show you a short line than in the fourth frame. Your line becomes longer. In the fifth frame, your line becomes even longer. So think of it like this. Here you have emptiness. Here you have this, here, you have this, here, you have this, here, you have this. And if you change that every 20 milliseconds, then what you will see is a line that becomes longer and longer. And that's the logic with pretty much everything here, but with small modifications. But that's the very idea of Python animations. You define your objects and then you use this FuncAnimation function to jump into this optic plot function where your num variable increases all the time. And then you put your objects inside this function where at different frames, you extract different elements from your arrays, from your time arrays, displacement, rail arrays, et cetera. And that's how you animate in Python. Like I said, to really explain everything. It really requires a separate course because you do have a lot of nuances there that you need to take into account. So that's it on this PID train explanation. And I'll see you in the next video. Thank you very much.
38. Quick code & animation explanation (water tanks): Welcome back. I've decided that I'm also going to create a small video about explaining this code file for the water tank. So let's go through it together. This radius here, that's the radius of the tank. So you can imagine that your water tank is cylindrical. So this is the radius of the circle that is on the x, y plane. So in the simulation, you see that the water tank is like this. But actually your water tank is a cylinder. So it looks something like this. And so here you have your radius. So this radius here, that's your five meters, that's this one here. Then this here pretty much says that the minimum of volume of water that you can have in the tank, it's 0 kilometers, which makes sense. And then you also have the maximum volume that should war tank can have that sure. One hundred one hundred cubic meters. They do not tell you how much water you actually have in the tank is just it shows you that, okay, this is the minimum value and then this is the maximum value. And the reason why I do that is because in the simulation, you see that you have here 0, then you have here maybe ten, and then 20 up until 100. So these values here, they are my volume value, show if this is the level of my water here, will thus just means that I have 20 cubic meters of water inside the tank. And so this bottom equals 0. That's just to establish this level here, the 0 level. And then this final volume. That's just to establish this level here, the maximum level. So the volume equals ten, that's the change of volume on the vertical scale. So it's essentially this difference here. That's your d volume. Alright, that's this one here. And so this width ratio here, that's necessary for the horizontal axis. So here you see the simulation and that with the ratio essentially determines that, okay? Here you have 0, then here you have five, and then here you have minus five. So it governs this horizontal axis. Then your D T is your time interval. So it means that you have a time vector and then this time vector with the 0.04 time interval would be something like this. 0 then 0.04, then 0.08. And then etc. All right, up until you reach your final time, or t sub n. And then this is the initial time of the simulation. So you start from 0 seconds and then you finish at time equals 50 seconds. And then this is frame amount. And that's for the animation. In the end of this code. In this section here, you determine the parameters necessary for your animation. And one of the parameters is frame amount. So you can think of it like a movie. A movie consists of several frames, are actually, there are many frames, kinda like snapshots in time, like pictures. And then you change those pictures very fast and then you have a movie. So here you determine how many pictures you have. And then well here you create your time vector. You go from 0 up until 50 plus 0.04. And the reason why I have to put it like this is because remember in Python, the last number here is not counted. So if I put here 50, then I'm gonna go from 0 till 4.96. So I have to put here 50.04 in order for the last time element to be 50 seconds. And then this is your density water, 100 kilograms per cubic meter. And then these are your proportional constants for your first, second, third tank, because it's your proportional controller, right? So these are your proportional constants. Then this is the initial volume of your first tank. So if your initial level of water is 30 meters, in terms of volume within that just means that at time equals 0 seconds, this would be your water volume. And then this is the initial water volume reference value. So 70 kilometers, that's where you want to be. So I can say that, okay, this is my initial volume reference value, which is 70 cubic meters. And of course this is not up to scale. And then here it's the same thing only for the second tank. And then also here you have the same thing but for the third tank. Now your initial true volume and then your initial reference volume. These were your initial values, but they will change as a function of time. So in order to keep track of all those numbers, you need a vector for them. So for the first tank, you have your 0 vector that has the length of the entire simulation. You see len t. You will have a vector containing all these elements. And inside this vector you're going to be storing your reference values as a function of time. And the same thing with true values. You create a vector in which you're going to be storing your true volume values. And here you insert the initial true volume as the initial element of the vector. So you see I have the 0 here, and that's my initial volume, which was defined here, 30 meters. And that's going to be the first element of this vector. You also create a vector for the error. And the amount of elements that you have in this error vector will be equal to the length of the time vector. And since this one is a 0 vector, then if you take the 0 vector and then you multiply it by this proportional constant for the first tank. Then you will also have a 0 vector here. So this 0 factor here, that will be the place where you're going to be storing your mass flow values, show your control input values. And the same thing for the second tank. In the third tank, it's a little bit different because in the third tank, I define my reference values for the entire simulation. So you see, I have this function here and then I take this T, which is a vector that goes from 0 seconds till 50 seconds with this 0.04 interval. And so I will get a reference vector for the third tank. And then the elements will depend on the time values and dysfunction in general. And you see this variable here, that's this variable here, 50. In other words, in comparison to other tanks, here, you don't create a 0 vector for the reference values where you're going to be storing those values in the future. Here you create a reference value vector right away. And then everything else is the same. And then you start the simulation, not the animation, but Simulation. Animation comes later. Animation is the part that creates this movie so that it would be fun to watch. But then the simulation that's actually computing the values in going through the control loops and et cetera. So here in this for loop, you see that sure, i goes from one up until the number that is equal to the length of the time vector. So the length of your time vector is here, one hundred, two hundred and fifty one. But since the last number is not counted, so your i will go from one. By the way, the one is counted. So in Python, the first number is counted. So if it's one here, then your i will be one. But then if it's one hundred, two hundred and fifty one here, then the last i that you will have will be one hundred, two hundred and fifty. And so if your i is less than 300, well then you determine your reference value vector for tank 12 for this region if it's less than 300. So basically you're saying that if your i is less than 300, then the reference value for the first tank will be this one here, which was this one here, 70 cubic meters. It means that it's constant. And then you have this second tank. And here the reference volume values will not be constant. They will be dependent on time. You see here you have your time vector and then here I put this i here. So every loop I will be extracting some kind of element out of this time vector. And so I will have a different number here. And so I will have a different reference value for tank two. But essentially you can see that this is a linear function with an offset. So this is like y equals a times x plus b. And now instead of x you have time. And instead of b you have this initial reference value for tank two, water volume. And then this a here, that's your three. You see that's just three. And then your y here. That's this one here. So you take your vector that you had previously declared. You made it a 0 vector for storing reference volume values. And now you store the volume values inside this vector. And then the same thing happens if your i is less than 600, but greater than 300. Because if your i is less than 300, then it will never reach this block. It will always enter this block first. But then if it's greater than 300, then it will skip this block. But if it's less than 600, then it will enter this block. Then if it's greater than 600 but less than 900, then it will enter this block. And if it's greater than 900, then it will enter this block here. And essentially these blocks, they tell you what the reference values for water volume r. So you see that here, it's first 70, then it's 20 cubic meters, then it's 90 cubic meters, and then it's 50 kilometers. That's for tank one. But for tank two. I have a linear function here with an offset, and then it continues here. So you see here now I have another equation for tank two for its reference values. And then here as well. So if you see, then this is your reference value here for tank 170 kilometers. And then it changes to 20 cubic meters, and then it changes to 90 cubic meters. And then it changes to 50 kilometers. But you see for tank to the reference value follows a function, linear function. And so here, when it starts going down, then that's when you enter this block here. And so you see that your reference values here, they follow a linear function with an offset. And then in tank three, you have another function for the reference values. For tank three. You see it's a very chaotic sinusoidal function. And so here it's the same thing that's when you are equal to 900 or greater than 900. So these were all for the reference values for tanks 12. Essentially here, what you've been doing, it's what you did here with tank three. In tank three, you determined your reference values right away. But then in tank 12, you first create a 0 vectors. And then here you would fill in those 0 vectors creating some kind of reference value vectors. And then here you compute your errors. So your reference value vector at certain I minus1 minus the true value in the volume tank at i minus one. And then here I compute my control inputs. You see, I have my proportional constants here, and then I have my errors, and then I compute my control inputs. And then through this numerical integration that we have studied in this section, I compute new values for the volumes in tank one, tank two, n tank three. They are my new water tank volumes. And then when I start with a new loop, then I will compare these values to the new reference values. And so this loop here will go back and forth until the end of the simulation. And that's the end of the simulation. Starting from here, I start with the animation. In this animation, I have a special function here called update plot, that's a feature of matplotlib. And then it has this special variable num, which is also a feature of matplotlib. And so this num variable, it will run from 0 up until the amount of what you have here, frame amount. And so this num variable will be like this. It will be 0, then one, then two, up until the number that you have for your frame amount. Okay, till here. Now, the thing is that what can happen many times is that this num variable at the beginning will be 0 and then again 0 and then it starts counting 123 until frame amount. That's a feature of matplotlib. And I don't know exactly why they did that. But perhaps there is some kind of reason for that. I don't think that it's a bug or something. So at the very beginning, you're going to skip this function. And then your program will move here where you will define your figures and then you define your objects. So what you see here, it's a figure full of objects. For example, this red line, an object, this one, and then also this blue area, that's also an object. And then these lines here, they are objects. And so I define them here for tank one and then for tank two, for tank three. And then also for this lower graph. And by lower graph I mean this one here. So I define all these objects there. So for example, this blue line here, it's this object here, T n k sub one, so tank one. And then your program comes here. And then here you say that, okay, I'm working with this figure Fig, which is this one here. Then I have to go to the function called update plot. That's this function here. Then here I tell you how many frames I have. So my frame amount, then this integral, that's how fast I go from one frame to another. So 20 means 20 milliseconds. Then repeat equals true means that when your animation is over, what will happen then if it's true, then the animation will start all over again. But if it's false, then it will not start again. And then bleed equals true. That's also a Matplotlib feature. I've tested that it makes the animation more efficient. It deletes some unnecessary pixels so it determines what pixels are necessary and what pixels are not necessary. And then it deletes the unnecessary pixels. I think it does that. But if you put here false, then your animation will not be that nice. And then after that, you go into this function here. So this part here, this is like a safety feature. So I want to avoid a situation where my num is bigger than the size of a vector. So let's say that if I have ten elements in a vector, so if that's my vector here, and then I start counting from 0, and then up until nine, then in total, I have ten elements here, but I start counting from 0. That means that the last number that minimum can be is nine. So if I have my vector here and then I put nine here, or num, which is nine in this example. Then what's going to happen is that I will extract this element out of the vector. So actually it doesn't have to be a nine. It can also be an eight or 85 or whatever number you have here. But if you're num equals nine, and then you put this nine here, then you will extract this element here. And then you will have, for example, 85 here. Put a what if for some reason num equals ten? So if I put ten here in the index, then I will get an error because there are no more elements in this vector. And so here I essentially say that if my Num in this particular example is ten, then subtract one from it and make it nine. That's the purpose of this section here. And we'll hear, I simply animate things. So this is for tank one, this is for tank two, and this is for tank three. And so for example, let's take this blue line here in this subplot. The object for this blue line is this one here. And so here I say this blue line set data. Then this is for the horizontal axis here. And then this is for the vertical axis here. So let's say if my num equals 15, for this example, let's say that my num equals 15, then that means that I have 15 here, right? Instead of nom, I could put here 15. And then instead of now my kid put here 15 as well. So from this time vector, I take the elements from 0 up until 15. And the same thing from this volume tank. One vector that I got from my simulation. It's this one here. So from this vector, I take elements from 0 to 1515 will not be counted here because in Python the last numbers are not counted. So you will have 15 elements that you will take out of your time vector and your volume temp one vector. But those 15 elements, they will start at 0 and then they will finish at 14. And then if you do that, then you will create a line here. Then the next time you call this function, your num will be 16. So you put here 16 and then you put here 16. And then you will have a little bit longer line. And that's how this animation works. And then you have to take these objects here and then you have to return them. Now one final thing you might be wondering why I have 63 here. These numbers I got from trial and error. This object here, tank sub 12. That's this blue area here. But in reality it's not area. In reality, if you look at it, then Tank one too. It's just a line with a huge line width. So you can imagine that I have my tank here. And then I want to create some kind of blue area here. And so I create an object here, which will be a thin line. But I want the thickness of this line to be as thick or as wide as this tank. So if I put 260 here, which is a pretty big line width, then this thin line will become a very thick line. Alright? So it will be a very thick line. And then I can use it to represent water in the tank. So this is not simulation, this is just for animation purposes. The problem is that if I give such a huge sickness to this line in the horizontal direction, then this line will also become very long in the vertical direction. And so the height of this line will still vary according to the data that I get from the simulation. So right now it's here. And then if the water volume goes down, then this thing here will go down. And then also distinct here will go down. But still you can see that this is nonsense because that's not what I want to represent. So through trial and error, I found that I if I put minus 63 here and minus 63 here, then I'm essentially cutting off this extra area that I don't need. So I still have the thickness of this line, but I don't have the stuff that I don't need any more. And so the only thing that I have, I have the area that I'm covering inside my water tank that very closely follows this line here. You see 70 here. Then it was 70 here, and now it's 20 here and 20 here. So if I put here, for example, minus 50, and then I'm going to put here minus 50. Then you see I should be at this 70 cubic meters, but I'm a little bit above. You see here as well. I'm a little bit above. That's this extra area here that I don't need. So this number here minus 63, and then here's one minus 63. That was just my trick to create this animation. All right, I hope that this video has clarified this code file as well, and I'll see you in the next video. Thank you very much.