 Tonight I'm going to talk about my quadcopter project. First of all, I just want to introduce myself. My name is Ryan Boland. I'm a, despite the fact that embedded programming is a hobby of mine, it's not my day job. I'm actually a web developer. I work with Rails mostly. I work at a small consultancy called Tanuki Labs. We have some big clients, some small clients. And we have some clients that we're excited, but we can't tell you about yet. So, and we do great work. So if you're a developer who's looking for some work, or if you need some developers, you should look us up. So I'm going to kind of jump right into it here. You guys have probably seen them flying around, or maybe read about them on the internet. People doing illegal things with them. But essentially there's not much to it. It's almost like a helicopter with four different propellers. And these propellers spin at different rates in order to maneuver the quadcopter. Here is a picture of my project. This is actually the first version of my project. So it's come quite a long way since I took this photo. How did I get into this? Last summer I started this project actually with a lot of research. And I saw these things flying around, and I saw them online. And I decided it would be cool to build one. But I kind of wanted to take it a step further. I didn't want to just build it and use a stock flight controller with code that somebody else wrote. I actually wanted to build the flight controller myself and see if I could program it myself and come out with a reasonable result. So I'm not going to tell you so much about how I built this thing, but I'm going to talk a lot about the software that actually makes it run. So let me just give a quick overview of my talk here. First of all, I'm going to give a rundown of just the basic components of the quadcopter. After that, I'm going to give an overview of some of the physics behind how it works, how does it maneuver, and things like that. After that, I'm going to discuss how we can take the raw sensor inputs and manipulate them into usable data that we can use to control the quadcopter. After that, I'll talk about how we can take those sensor inputs and convert them to basically four numbers, a speed for each one of the four motors. That would be the motor outputs. And finally, I'm going to talk a little bit about safety because when you're working on a project like this, it's very important. So into the components. So my slides are a little off-center here, but I don't think that's a problem yet. So the components, we'll start with the frame. Pretty basic. I started out with a frame that's more like the one on your left up here. And while it looks pretty cool, unfortunately, anytime I crashed the quadcopter, one of those little screws or little pieces broke. So I actually moved to a simpler frame, like the one on the right, has far fewer parts. And I found that for testing purposes, that's very far superior because there's no little pieces that are going to break. The worst thing that can happen is you crash and break one of the entire arms. But that's why you just buy like two of the frames in case you break anything. Next up are the electronic speed controllers and the motors. So I have my electronic speed controllers mounted on the bottoms of the arms. And the motors obviously are mounted at the end of each arm. Essentially what the electronic speed controller does is it acts as an interface between the microprocessor and the motors. The motors run at a much higher current and voltage than the processor. So the electronic speed controller makes it very easy for us to communicate with the motors. Basically, we tell it how fast we want the motor to go and the speed controller takes care of actually operating the motor. The motors are brushless DC motors. That means anything to anybody. So I started with an Arduino Mega, which is on the far left, just because I didn't really know where to start when I started getting into this. The problem here is that it's quite heavy and it has a lot of inputs and outputs. I realize I just didn't need all of those inputs and outputs. So I moved to a smaller device, which is the center one. And that's an Arduino Nano. And I actually have the prices here so you can get an idea. The center one I bought off of eBay in a pack of like five and it works out to be even less than $5. You do a little more work in order to program it and solder it in and everything like that, it's much smaller and it has less program memory but it's equivalent speed to the Mega. And finally, very recently actually, a couple of weeks ago I got this teensie and it's far more sophisticated in terms of speed, program space. The biggest thing actually is that it's about six times faster than the Arduino's. So that allows me to have some flexibility and basically not be constricted by the speed of my microcontroller. It's definitely possible to run these flight quadcopters on an Arduino. My first iteration, I used it. It's just, it's less convenient in terms of programming and stuff like that. Now the other thing I needed was an inertial measurement unit. I talked briefly about this before. This is the one I picked up off of eBay again. So it has a three-axis gyroscope, a three-axis accelerometer. It has a magnetometer which is used to measure compass heading. And it also has a barometer again to measure altitude. I'm gonna discuss in detail the gyroscope and the accelerometer. I haven't incorporated the magnetometer or the barometer into my project yet. So where to kind of buy these components now that we've talked about the components. Usually if I can get something on eBay, I usually do unless the seller has bad reputation or something like that. It's far and away much cheaper. It takes like a few weeks to get here but in the end it's definitely worth it. You can just like buy, stop, involve, completely rack it and you only waste a couple dollars. So that's definitely the place to start. For the more hobby related stuff like the frame and all that stuff, I use Hobby King. There's a lot of alternatives in that space as well. And then for some of the stuff that I can't buy on eBay like the TNC for example, I had to get from Spark Fund. It's a US based company, great company, but a lot of their stuff can be overpriced. So you've gotta be careful and just do a price comparison. So now let's get into a little bit about how the quadcopter maneuvers itself in some of the physics behind. Okay, so when you're building your quadcopter, one of the first things you should decide is whether you wanna do a plus or an X configuration. The main difference is basically what is the front of the craft? I've chosen the X configuration so the front of my craft is represented by the red arms. So I always know when I'm flying it from a distance, I can tell how my controls are gonna work because I know where the front is. There's really no difference between these configurations. It's kind of like personal preference. I think the X looks a little bit cooler, that's why I picked it. So the orientation of the craft is important when you're designing the software. So we have obviously three axes that we can rotate about. The first axis we have is the X axis which is also known as roll if you are speaking with someone like with an aviation background. And that would be just a movement like this. So you're rolling to the right or the left. We have pitch which is basically a forward or backwards movement. And we have the Z axis which is yaw and that's basically just a turning movement like this. The quadcopter maneuvers itself, it's pretty basic. In order to perform any of the four movements, we kind of just look at this chart. If you wanted to increase your altitude, you would basically just increase the speed of all four motors uniformly. And that would obviously increase the altitude of the craft. If you wanted to pitch forward for example, to go forward, you would have to increase the speed of the back two motors and decrease the speed of the front two motors by the same amount. And that would basically raise the back of the craft and propel it forward. Same with roll, you would increase the speed of these motors and decrease the speed of those motors. Now yaw is a little bit different. The reason that the craft doesn't spin out of control is because the diagonal motors spin different ways. So that basically counteracts the spinning motion so that the craft can remain stable. And if you would like to pivot or yaw the craft, you would have to increase the speed of the diagonal set and decrease the speed of the other set. And that would produce like the yaw motion. Here's just a demo, a quick video, one of my first test flights outdoors. It's kind of a bad video. But I haven't got to fly it outside very much just because of the weather. So I kind of put this video right at the perfect time before the weather got bad. So building it was actually pretty fun, not too stressful. There's not much you can screw up when you're building it. But then when you get into the code, it's really the meat of the project. It's the real challenge, the code and the tuning. So I'm gonna actually just dive right in and start talking about that. Here's, if you look at the code I have now on GitHub, it doesn't look quite like this, but this is sort of my first more naive implementation. And this works fine. And I've also stripped out some debugging stuff. So the code is just less noisy. But this is actually pretty realistic code here. If you've worked with an Arduino before, basically we have a setup function and we have a loop function. The setup is performed once when the processor starts up and the loop is performed over and over again. This is the loop code. And basically I'm gonna structure my talk a little bit around these three function calls because this is really the main gist of the program. So I start by reading the sensor values. And my, as I said before, my inertial measurement unit is located right here on the flight controller. And the two main values that I need from that is rotational rate in degrees per second. And I also need angle in degrees. And so basically I have to read the values from that device, manipulate them into something that I can use, basically the rotational rate in the angles. So let's move on to that. Like I said, first thing is orientation. I need the rotational rate of x, y, and z. And I need the angles, the x and the y angles in degrees. So I'm basically assuming here that you have your own device. I'm not gonna make this device specific because you can get your own inertial measurement unit. Basically I'm gonna assume that you read the data sheet and you were able to pull off raw values, read raw values in from the device, and you have some raw values in degrees per second. So this is just the dump I took and I put it into Excel so I could graph it a little bit to see what was going on. So when I graph it, you basically notice two things right away. First of all, it's noisy. It's not exactly a straight line. That's okay. The noise is pretty minimal. Although when your craft is flying, it does vibrate a lot so the noise gets worse. That's why if you come up later on and look at it, I've got some dampening pads that basically isolate some of the vibration as the craft is moving. The other thing you might notice is that it's offset. So despite the fact that the craft wasn't moving, the values are all kind of centered a little bit below negative 2.5. In order to correct that, basically it's very simple. All we do is take the average of all of the values and I actually do this in the code. So I have it like an alternate startup, excuse me, startup routine that basically takes the average and then it subtracts the average from every single value. And by doing so, you can see the bottom graph basically centers everything around zero. So we have, it doesn't look like the craft is moving when it's actually not. This is basically calibrating the gyroscope in a way. And believe it or not, that's all we have to do for rotational rate. We just take those values and offset them and then we have good rotational rate values. The people I've talked to in my experience also, you don't wanna filter the gyroscope values very much because you want it to react very quickly. And if you apply an averaging filter or something like that, it delays all of the values. So your craft might change directions but it might take a second to the filter to catch up and realize that it changed directions. So you basically wanna have your gyroscope values as raw as possible. One kilohertz, actually eight kilohertz but the processor just doesn't do it that fast. And that's just a very hobbyist device. So if you've got an actual gyroscope that might be used professionally for something, it's probably faster than that as well. So the next thing you wanna do is get the angles, the x and the y angles and degrees. So let's see, try to reason a little bit about how we might use the gyroscope to determine the angles. So let's imagine that our quad is, when you start it up, it's laying flat. And then, so our angle right now in any given in x or y right now is zero. Then let's say we rotate five degrees per second for two seconds. I'm just gonna pick an arbitrary direction. So we might be then, we might be at 10 degrees. After that, we rotate back 10 degrees per second for two seconds. So now we might be at negative 10 degrees. And after that, then we go ahead and rotate five degrees per second for one more second. So we might be at negative 15 degrees. So if we continually sum up the rotations, we can get an approximation of what angle the craft is at. So this is calculus, this is integration. This is approximation of an integral. And the equation at the top, so we're basically just taking the integral of the rotational rate. And so let's translate this into code so we kind of understand it a little better. Hopefully you guys can read this a little bit. So basically, since we're doing an integral, we need to measure the time between readings. Or do we know it has a function called micros which gives us the current microsecond count? So we're gonna get the last update time in microseconds. That's how we're gonna initialize that value. And then we're going to do the gyroscope reading. And we're gonna apply that offset that we talked about earlier so that our values are centered around zero. After that, we're gonna calculate the delta time, the time between the last reading. We're gonna divide by 1,000 because we're working with microseconds, or I'm sorry, a million, is working with microseconds. So we're gonna convert that microsecond difference to seconds. And then we're going to take our x angle and we're going to multiply the rotational rate by the delta time. And we're gonna add it to the angle. And then obviously we're gonna record the time so we can use that on the next reading. So this is just a very simple approximation of the integral so we can get an idea of what angle the quad is at. So I'm gonna give a quick demo here to show you how the approximation does. And I have this Chrome extension that I built, basically as sort of a dashboard to make visualizing the data from my quadcopter a little bit easier. So when I toggle this on here, the value that we're looking at is this light blue value. So when I rotate the craft, you can see that if I'm maybe at 30 degrees or so, talking about, okay. So as I rotate the craft, the angle seems to be updating, but when you hold it steady overall, the angle actually drifts. That's why our value is off centered. So locally, we're approximating the angle very well, but over a long period of time, the value is just drift. So we have to somehow correct that drift. This is called gyroscope drift. And the reason this occurs is that between our readings, the gyroscope changes rotational rate many times. And the only thing we capture is the very last rotational rate. So when I rotate the craft in between samples, it might have changed rotational rate a hundred times or a thousand times or infinitely many times, but I only captured the very end. So I have like a flawed sample. So that's why this drift occurs. So if we're looking back at our goals for reading from the sensor, we've accomplished our rotational rate goal again, but we have an approximation of the angle, but it's not quite good enough yet. So this is where the accelerometer comes in. It's located on the same chip as the gyroscope and it measures acceleration in terms of G force. So again, I'm gonna assume that you can communicate with the accelerometer and pull off some raw values from it. And it's gonna require the same offset calibration, very similar to the gyroscope, but with one notable exception. So you would calibrate the X and the Y axes as normal, you want to calibrate them to zero, but the Z axis should be calibrated to one G because if your quadcopter is laying flat, you have one times the force of gravity coming down on it. This is a mistake I made when I first started. I was kind of gung-ho on getting all the offsets to zero. So this screwed up my angle measurement here when I first got started. So from the accelerations, excuse me, you can use these formulas to compute the angle that the craft is at. I'm not gonna attempt to derive these formulas because I don't fully understand them myself, but there's a great PDF at the bottom here if you're interested. It goes through step-by-step and derives these formulas. So we can take again and put these into code and get a better understanding of how they work. So this is where the accelerometer differs a little bit from the gyroscope. You do want to filter the accelerometer data because it's very prone to spikes, vibration and spikes. So what I'm doing here is applying a median filter. I'm not gonna describe how the median filter work. I'll describe it, but I'm not gonna show the code for it. Basically you have a window of previous values and you order that window and take the median. So maybe you record the last, I think I record the last 11 values and when a new value comes in, I sort the array of values, take the median and I choose that as my new value coming in from the accelerometer. This helps to eliminate some of the spiciness and stuff like that. These two lines here are basically just a straight copy off of the formulas above. With Arduino, we have this arc tangent function. I'm actually not sure where that comes from, but we have the arc tangent function and the only other thing to note here is that we are converting these from radians to degrees. So we're just gonna multiply a constant in there. So how does this do? Well, I'm not gonna show a demo of this one, but when you level the craft, the value is indeed zero. It is centered about zero and it doesn't drift. However, any slight vibration that happened at the end there causes spikes in the accelerometer. So what we have here is an accelerometer that's susceptible to vibrations again. So we have to combine these two approaches. We have to combine our estimate from the gyroscope with our readings from the accelerometer. Gyroscope is great for short durations because it responds very quickly and it's very accurate and the accelerometer is good over long durations because it always returns to zero. It doesn't drift. So we can use something called a complimentary filter. This isn't the best approach, but it's very simple when it gets you really close, close enough. And so basically we have to define two constants. They add up to one. We have a part for the gyroscope and a part for the accelerometer. We get our delta time, our time since the last combination again. And basically we take our final angle output is going to be the gyro constant times something that looks very similar to our integral approximation. So we're going to multiply the rate times the delta time and we're gonna add that to all of the previous angles that we've calculated before. And then we're also gonna have this, we're gonna add in this accelerometer part and we're gonna multiply the accelerometer reading by this constant. You can change these constants. You can change these constants, but these have worked well for me. I'm not sure the rules behind changing them, but you can experiment with that. So now I am gonna show a quick demo of how the complimentary filter performs and gave away my secret. How the complimentary filter performs against the other estimations. So here in this graph, I have three different readings. Again, the light blue is the gyroscope approximation. Sorry, bear with me for a moment. This will get much easier to see in one second when these old values fall off. The light blue is the gyroscope approximation and you can already see that it's starting to drift away from the other values. The red is the accelerometer and as you can see, if I just give this a slight vibration, it spikes up and down. Now the darker blue is our complimentary filter and you can see how it basically hugs the accelerometer values, but it doesn't have any of the spikiness that's associated with reading from the accelerometer. So this ends up being a very good approximation of the current angle of the crown. Obviously, so this is the X axis, but we also do all of these steps for the Y axis to get an approximation of that angle as well. So we've accomplished both of our goals and this was kind of took a while, so we're gonna celebrate. And we're not gonna celebrate too long though because now we're gonna move on to the next part which would be reading the values from the remote control, the pilot inputs and interpreting them to some usable values here. This part I'm actually gonna just skip over pretty quickly with just one slide. It's not very interesting and you can read more about this in this blog post down here. Basically, the remote control gives us values that range from 1,000 to 2,000 microseconds. So it basically gives us pulses that range from 1,000 microseconds to 2,000 microseconds. So for example, the throttle, if I throttle all the way down, I'm at 1,000 microseconds. If I throttle all the way up, I'm at my signal is gonna be 2,000 microseconds. So I can take, and that works the same for each of these controls here. So I can take the minimum and maximum inputs and map them to whatever values I want them to be. So for example, I wanna give the pilot the ability to pitch and roll up to 25 degrees in any direction. So I'm gonna take my 1,000 to 2,000 and map it to values between negative 25 and 25. Then I'm working on with the same units. This is degrees here on the right. So negative 25 degrees to 25 degrees. Pitch works very similarly and same with yaw. Throttle, I'm gonna go ahead and leave the default value of 1,000 to 2,000 because that works very well with the electronic speed controllers. The electronic speed controller is also expecting, for each of the motors, it's expecting a value between 1,000 and 2,000. So it works out to just leave the throttle alone, take the raw values there. So now I've read my remote control values and I'm ready to do this last part, which is the flight controller process. Basically the flight controller, it's not any piece of hardware, it's just code, but it's the code that's responsible for taking the sensor values and the remote control values and converting them to some useful motor outputs. So again here, when controlling the motors, the motors are basically made to work, except the number between 1,000 microseconds and 2,000 microseconds. So this is our goal. We need four numbers from our flight controller. We need four values between 1,000 and 2,001 for each motor. Quadcopters have several different modes that you can operate them in. One of these modes, the easiest one to implement is rate mode. And with rate mode, basically the quadcopter never tries to stabilize itself, but instead it always tries to maintain the same angle, not rotate. Here's a quick video of how this works. So when I issue an input on the sticks, I'm telling the quadcopter to rotate at a set rate. When I release the sticks, so right here I release the stick and the quadcopter is attempting to stay at that angle. It's attempting to get its rotational rate now to zero degrees per second. This mode is easy to implement, but it's actually more difficult to fly because you have to manually adjust the quadcopter back to a level of height. So when I'm working with the flight controller code, I have three problems. And these problems correspond to all three axes. I could be tilted forward. That could be a problem. I could be tilted to the right. That could be a problem. And I could be rotating. I could have an undesirable yaw. When I release the sticks, I really want the quad to not rotate about any of those axes. I want it to hold perfectly the angles that it was at previously. So I need to figure out a way to correct the three of these problems. Now, like I said before, we're looking for four numbers, motor one through four. And those are our four outputs to the speed controllers. So the first thing we're gonna do in this equation is actually just add in the throttle. And if you think about this, it makes sense because if we want the quad to hover, all we have to do is increase the throttle that uniformly increases all of the motor outputs. So it's gonna increase the speed of all four motors and the quadcopter is gonna fly higher. After that, we are adjusting our three problems, roll, pitch, and yaw. But if you take note here, all of the signs are different. Each one of the motors gets assigned a different set of values, signs. So we're adding and subtracting differently for each motor. And the reason we do this is because each motor has to compensate for each problem differently. So taking roll as an example, I have motor one here. If I'm rolling to the right, motor one has to increase, but this motor has to, I'm sorry, this motor has to decrease, whereas this motor and this motor need to increase. So these two motors are gonna get one value, one sign here, we're gonna add them, say add the pitch value or the roll value in. And we're gonna subtract the roll value here. So basically we come up with almost like a matrix of signs here. And you basically just have to study, you know, move the quad like this, look at each one of the motors and say, you know, okay, I have to increase the speed on these two motors. So those are gonna get a plus sign. Back here I have to subtract the value in order to compensate. So that's where this big matrix of like plus and minus signs come from. And these, the signs will be different if say your inertial measurement unit is mounted differently or it's, you know, mounted backwards or something like that. So let's take just the first motor as an example. We know we have to adjust for roll pitch in yaw, but we don't know how to calculate those values. How much should I adjust for roll? We're gonna use here a PID controller. This is getting into the control theory a little bit. It's a proportional integral derivative controller. It's going to basically the block diagram at the bottom. It's gonna take the rotational rate from the sensors and it's gonna take the desired rotational rate from my remote control. And from those two values, it's going to produce a motor output. And that motor output on the bottom, I would need three of these PID controllers. I would need one for roll, pitch, and yaw. So how do I implement the PID controller? First of all, I'm not gonna use derivative here because it's very susceptible to noise. So it's sometimes easier just to not use the derivative value. So I'm gonna end up with a PI controller, proportional integral. Basically, we compute an error that's based on the set point and the input. So if I was telling the craft to stop rotating, but the craft was actually rotating at five degrees per second, then my error would be negative five degrees per second. I have to compensate for that undesired rotation. So how I compensate for that is with this PI equation. The proportional term compensates for the present error. And the integral term again sums all of the previous errors. So if we have some kind of systemic error, maybe one side of the craft is heavier or something like that, the quad will all continue summing until eventually it overpowers it and stops the rotation. So just real quick on how to implement this. The hardest part of this is determining the constants. We need a constant for the proportional term and a constant for the integral term. And you have to basically be very patient in manipulating these terms and analyzing the results and then continuously see if it was an improvement or it adversely affected the stability. So once we have our constants there, we're gonna compute the error. The error is very easy to compute. It's the desired pitch or rotational rate, whatever it might be, minus the current pitch or rate. And then from that error, we can compute the proportional and integral terms. The proportional term is just Kp times the error. And the integral term, again, it sums on itself. So it's constantly increasing or decreasing. And it's the error times the integral constant times the delta time since the last computation. Finally, the output is the sum of the proportional and integral terms. So like I said, we need one of these PI controllers for each axis. We need one for roll, pitch, and yaw. And that's what these adjustments end up being. The PI controller, this equation on the past sheet, the past slide here, is the computation of the roll adjustment, the pitch adjustment, and the yaw adjustment. So then we take those and that's how we produce our motor outputs. We have another mode that I don't have time to cover tonight, but that's a stabilized mode, wherein the quadcopter is always trying to maintain a stable flight. So an angle of zero degrees in each axis. And in order to build that functionality, you need to build on top of the rate controller. So the stabilized controller, we have a new set of PI controllers for stabilization. And what they do is they take the actual angles and they take the desired angle from the pilot and they feed into the rate controller. So our stabilized controller is saying, hey, my angle is negative five degrees. And it tells the rate controller, could you please start rotating so I can compensate for this angle error? So basically we have three new PI controllers there. Again, I'm not gonna cover this in detail. And so are we ready to fly yet? Not quite. The hardest part here is the tuning. It takes a lot of practice to tune this properly, practice and patience. I built sort of a test rig where I found two of the axes so that it could only rotate on one axis. And I could, it's a lot safer because it can't fly out of control or anything like that. And it also can't crash. So this is a great way to get like an introductory set of values to tune the quad to an introductory set of values. So real quick, I see I'm running a little bit long. So I'm gonna talk about safety real quick. Safety is very important. This is my house. And back when I didn't think safety was important, I decided to be sitting here on the deck about a foot away from my quadcopter with it tied to the railings. And when I had a bug in the software that caused the quadcopter to accelerate uncontrollably, it crashed into the railing and my fiance and I were sitting right beside it. It crashed into the railing and some of the propeller just exploded into a million pieces. Luckily, we weren't hit by them but I was walking the dog the next day and I found pieces as far as over the house in the driveway. So there's kind of a close call there and it's incidents like this that sort of made me realize that safety is very important. I'm pretty scared of the quadcopter now. So what are some things that you can check for here? You can check for stale values from the inertial measurement. If there's some kind of an issue and it's giving you the same value over and over again, I have a check for that. But if any of these things occur, the safest thing to do is just turn off all of the motors. The quad is gonna crash but it's not gonna do any damage to people or property. Another thing you might check for is stale remote control values. The remote control sends you the same value 5,000 times in a row. It's probably not updating something happened. There's a bug somewhere. In my quad, I also have a check for the angle. So if I rotate the quad at too high of an angle, I think I have it set to 45 degrees, it just dies because right now I say that there's no way that the present algorithms can compensate for such a high angle. So it's gonna crash and evidently might as well turn the motors off. And also I've implemented an indoor safe mode. Basically if the motors go too high past a certain value, it's disabled automatically. So some takeaways. I'm gonna fly this thing a little bit here in a second. But some takeaways from the project for me. First of all, be safe. It's very important. You need to have your safety goggles, maybe gloves while you're working with it. And I probably, if I was doing this again, I might have started with a smaller project like a balancing robot. This project is very, very similar to the quadcopter project. You need, basically what the robot does is it has a weight on the top and it changes the speed of the motors in order to keep itself upright so it doesn't fall over. And it has a lot of the same components in it as the quadcopter, has the inertial measurement unit and you also get some practice with controlling the motor outputs. So maybe I would have started with a smaller, less dangerous project. And finally, working with a system like this, you really wanna break it down into the smallest parts possible and make sure that you really study each component, test it, make sure it's working. And that makes it a lot easier to combine it into the final product. I have some resources here. We'll try to make these slides available so you can check these out if you want. And thanks. I'm gonna be making some blog posts on a lot with a lot more detail about each one of these systems. So if you wanna follow me on Twitter, I'll be tweeting out those blog posts. So I'm going to do one final demo here. You'll have to bear with me for one moment. Hold things here. So I'm not a very good pilot. And it's gonna be even more difficult given that I'm doing this in front of a lot of people. So I'm just gonna try to hover it about the top of the ground. And I want you to pay attention to the ground at the top and the values of the motors. Each one of these gauges corresponds to one of the motors. So you can sort of visualize the fact that each motor is spending at a different rate. So what's the charm is showing up there? So my speed gauge is down on the motor. So there, I got three in the working case. The graph, the short and half meter at the top is basically that the green is the pilot paint, at a large spike here in the chart. So most of that follows off, you'll be able to see the green moving. And there's also a purple line that's gonna correspond to the actual angle of the graph. So you can see when I make, when I maneuver the graph with a stick, the purple one is gonna try to follow the green line. So you can see when I toggle the control, you see the green line spike up and then you see the actual angle of the graph begin to move towards that value. Now, it doesn't follow along perfectly and that's a lot of what the tune needs for. The better tune it is, the more accurately it will respond to the changes in their values. So that's it for me. Thanks for watching. Thank you.