drone-technolgy:pid-controller
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| drone-technolgy:pid-controller [2022/05/17 15:25] – ilgarrasulov001 | drone-technolgy:pid-controller [2023/01/05 14:38] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 74: | Line 74: | ||
| {{: | {{: | ||
| + | |||
| + | <file c arduino_code.ino> | ||
| + | // importing libraries | ||
| + | #include " | ||
| + | #include " | ||
| + | |||
| + | //define pins | ||
| + | #define MOTOR D3 // pin for motor control | ||
| + | #define PIN_POT | ||
| + | |||
| + | MPU9250 mpu; // sensor instance | ||
| + | |||
| + | // initial control values | ||
| + | float kp=6.8; | ||
| + | float ki=0.1; | ||
| + | float kd=1.8; | ||
| + | float multiplier=1; | ||
| + | float error; | ||
| + | float ki_error_range=10; | ||
| + | float desired_roll=38.0; | ||
| + | float pError=0.0; | ||
| + | float current_roll=0.0; | ||
| + | float PID_p, PID_i, PID_d, PID_total; | ||
| + | // time parameters for setting the frequency of reading sensor values | ||
| + | int period = 50; // milliseconds | ||
| + | float tme; | ||
| + | |||
| + | // serial input value | ||
| + | String serialInput; | ||
| + | |||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(115200); | ||
| + | Wire.begin(); | ||
| + | // connection to MPU sensor | ||
| + | if (!mpu.setup(0x68)) { // change to your own address | ||
| + | while (1) { | ||
| + | Serial.println(" | ||
| + | // delay(5000); | ||
| + | if (mpu.setup(0x68)){ | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | | ||
| + | } | ||
| + | |||
| + | // motor and potentiometer to output and input | ||
| + | pinMode(MOTOR, | ||
| + | pinMode(PIN_POT, | ||
| + | // set desired roll to the value, read from potentiometer | ||
| + | set_desired_roll(); | ||
| + | Serial.println(" | ||
| + | tme=millis(); | ||
| + | } | ||
| + | |||
| + | |||
| + | void set_desired_roll(){ | ||
| + | // -55 lowest, 20 max, 0 center, total 75 | ||
| + | // read potentiometer value, range is [1024-10] | ||
| + | int rot_1024= analogRead(PIN_POT); | ||
| + | // convert to 75 units system | ||
| + | int rot_75 = 75*(1024 - rot_1024)/ | ||
| + | // set desired roll | ||
| + | desired_roll=rot_75-55; | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | // set desired yaw in accordance to the last read from potentiometer | ||
| + | set_desired_roll(); | ||
| + | |||
| + | // read input from serial monitor | ||
| + | // format: < | ||
| + | // example: kp=1.5 | ||
| + | if (Serial.available()> | ||
| + | | ||
| + | serialInput = Serial.readString(); | ||
| + | int index = serialInput.indexOf(' | ||
| + | String variable = serialInput.substring(0, | ||
| + | float value = serialInput.substring(index+1, | ||
| + | // check variable name and assign the value to the corresponding variable | ||
| + | if (variable==" | ||
| + | kp=value; | ||
| + | } | ||
| + | else if (variable==" | ||
| + | ki=value; | ||
| + | } | ||
| + | |||
| + | else if (variable==" | ||
| + | kd=value; | ||
| + | } | ||
| + | else if (variable==" | ||
| + | ki_error_range=value; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // check the sensor data | ||
| + | if (mpu.update()) { | ||
| + | if (millis() > tme + period) { // if more than period seconds passed since last read | ||
| + | | ||
| + | tme=millis(); | ||
| + | |||
| + | // read current roll angle | ||
| + | | ||
| + | |||
| + | // error calculation | ||
| + | error=desired_roll-current_roll; | ||
| + | | ||
| + | // P calculation | ||
| + | PID_p = kp * multiplier* error; | ||
| + | |||
| + | // I calculation | ||
| + | // I component starts to accumulate and hence to affect the PID total only if it | ||
| + | // is in range of ki error range | ||
| + | if(abs(error) < ki_error_range){ | ||
| + | PID_i = PID_i + (ki *multiplier* error); | ||
| + | | ||
| + | } else { // else it is set to zero | ||
| + | PID_i=0; | ||
| + | } | ||
| + | |||
| + | // D calculation | ||
| + | // pError is previous value of error | ||
| + | PID_d = kd*multiplier*((error - pError)/ | ||
| + | |||
| + | // Total PID calculation | ||
| + | PID_total = PID_p + PID_i + PID_d; | ||
| + | | ||
| + | // trim the PID value if it is outside of [0-255] range | ||
| + | | ||
| + | if (PID_total > 255){ | ||
| + | PID_total =255; | ||
| + | } | ||
| + | |||
| + | if (PID_total < 0){ | ||
| + | PID_total =0; | ||
| + | } | ||
| + | |||
| + | // print PID and other variables' | ||
| + | print_pid(); | ||
| + | |||
| + | // send final PID value to motor | ||
| + | analogWrite(MOTOR, | ||
| + | |||
| + | // set pError value to current error value | ||
| + | pError = error; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // print variable values to Serial Monitor | ||
| + | void print_pid() { | ||
| + | Serial.print(" | ||
| + | Serial.println(current_roll, | ||
| + | | ||
| + | Serial.print(" | ||
| + | Serial.println(desired_roll, | ||
| + | Serial.print(" | ||
| + | Serial.println(abs(error), | ||
| + | Serial.print(" | ||
| + | Serial.print(kp); | ||
| + | Serial.print(" | ||
| + | Serial.print(ki); | ||
| + | Serial.print(" | ||
| + | Serial.print(ki_error_range); | ||
| + | Serial.print(" | ||
| + | Serial.println(kd); | ||
| + | | ||
| + | Serial.print(" | ||
| + | Serial.print(PID_total, | ||
| + | Serial.print(", | ||
| + | Serial.print(PID_p, | ||
| + | Serial.print(", | ||
| + | Serial.print(PID_i, | ||
| + | Serial.print(", | ||
| + | Serial.println(PID_d, | ||
| + | } | ||
| + | |||
| + | // not used | ||
| + | // sending values to PC | ||
| + | // may be useful in future | ||
| + | void sendToPC(int* data) | ||
| + | { | ||
| + | byte* byteData = (byte*)(data); | ||
| + | Serial.write(byteData, | ||
| + | } | ||
| + | |||
| + | void sendToPC(float* data) | ||
| + | { | ||
| + | byte* byteData = (byte*)(data); | ||
| + | Serial.write(byteData, | ||
| + | } | ||
| + | </ | ||
| + | |||
| Link to the code in GitHub repository | Link to the code in GitHub repository | ||
| Line 94: | Line 288: | ||
| The commonly accepted way of tuning is following: | The commonly accepted way of tuning is following: | ||
| - | First you start changing Kp coefficient, | + | First you start changing Kp coefficient, |
| + | |||
| + | D = Kd*de/dt | ||
| + | |||
| + | $$ D=K_{d}*\frac{\mathrm{d}e(t)}{\mathrm{d}t} $$ | ||
| + | |||
| + | Here, the smaller the period between measurements or the bigger the change in error, the bigger will be the final D component. | ||
| + | |||
| + | And finally, you can tune the I component. It affects the final PID value only when error is within the given range relative to desired yaw value. For example, if the error is too small for proportional P controller and the error didn't change since the last measurement, | ||
| + | |||
| + | To change kp, ki and kd in our experiment without changing the code, you can enter: < | ||
| + | * " | ||
| + | * " | ||
| + | * " | ||
| + | * " | ||
| + | |||
| + | Here the values should be adapted for your device. | ||
| {{: | {{: | ||
| + | |||
| + | For more examples of PID controller see nice videos on Youtube in Resources section. | ||
| ==== Resources ==== | ==== Resources ==== | ||
| - | * [[https:// | + | * PID controller on Wikipedia |
| - | * [[https:// | + | * PID controller code [[https:// |
| - | * [[https:// | + | * PID Tuning |
| + | * PID Tuning [[https:// | ||
drone-technolgy/pid-controller.1652793904.txt.gz · Last modified: 2023/01/05 14:38 (external edit)