Thread Tools
Sep 06, 2014, 10:25 AM
Quad is the new black
Just came across this thread while preparing to tune my new quad build (if it ever stops raining long enough in Syd!). Just a quick question on the range of values for k in the code.

For example :
int ku = ((constrain(rcData[POT_G],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
int kp = ku + 8; //range: 1.0-3.7

I'm not entirely sure how this gives the upper limit for kp of 3.7 when at a pot value of 2000 this should be 1000* 2/64 +8?
Sign up now
to remove ads between posts
Sep 06, 2014, 10:38 AM
Whoop the planet!
benedikt's Avatar
Thread OP
Im also not sure why this yields a maximum value of 3.7..
But it works. And once it worked, I stopped hacking and started flying.

Bloody rain is killing me.. Where is spring?
I think Im going to fly with in indoor plane guys in their gym on fathers day
Sep 06, 2014, 11:28 PM
Quad is the new black
No problem - I'll work it out eventually.

The last time I fooled around with Mwii was at v1.9. The software has grown leaps and bounds since then and hardware has gotten so much cheaper! I am looking forward to doing some realtime tuning (eventually).
Sep 07, 2014, 05:24 PM
Whoop the planet!
benedikt's Avatar
Thread OP
Maybe I should have mentioned.. This how I figured it out:
Set above line in the code, flash the firmware, open the GUI, bind the radio.
Then move the related AUX channel to minimum, click READ.
Move the AuX to maximum, click READ.
This will give you the two extreme values.
Sep 08, 2014, 01:13 AM
Quad is the new black
Thanks - it was exactly was I was going to do next !
Sep 09, 2014, 11:49 PM
Quad is the new black
I ended up using barneygs code from here (which you linked to on another thread) with the factors changed so that the default PIDs are at the mid point of the pots. I'll see what happens when I've a chance to head out.
Jan 21, 2015, 02:29 PM
Registered User
I was playing with this last night but realized that if I wanted to tune P, I, and D, I'd need 3-aux channel pots, whereas one is being used to control gimbal pitch. The other problem is I only have two available inputs to my control board at the moment, in addition to the current 5 (the additional one being used for flight modes). I wanted to use the 3-position switch and the pot above it on my transmitter to do all my tuning.


I decided to hardcode the flight mode in, since I never change it anyway. Thus I spoof the rc setting such that it places the controller in horizon mode:

Code:
    for(i=0;i<CHECKBOXITEMS;i++)
      rcOptions[i] = (auxState & conf.activate[i])>0;
    
    rcOptions[BOXHORIZON] = 1;  //added line: Override to Horizon mode default:
This frees up an aux channel, but more importantly allows me to use the 3-position switch to flip between P, I, and D tuning. I changed the defines in the config to:
Code:
    #define DIAL_TUNING_BG
    #define POT_PID PIDROLL
    #define POT_P AUX1
    #define POS_SW  AUX2
And then placed the code in the annexCode() function -- which is basically the same as the code at: http://www.multi-rotor.co.uk/index.php?topic=5148.0 with a few minor tweaks to allow the 3-position switch to control what we're tuning.

Code:
  #if defined(DIAL_TUNING_BG)
    int posSw = (constrain(rcData[POS_SW],1000,2000));
    int ku, kp;
    
    if (posSw < 1300) { // Switch LOW = tune P values
      ku = ((constrain(rcData[POT_P],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
      kp = ku * 6 ;
      conf.pid[POT_PID].P8 = kp;
      if (POT_PID == PIDROLL)
	      conf.pid[PIDPITCH].P8 = kp;
    } else if (posSw <1700) { // Swith MIDDLE = tune I values
       if (POT_PID != PIDMAG){
	   ku = ((constrain(rcData[POT_P],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
	   kp = ku * 6 ;
	   conf.pid[POT_PID].I8 = (kp << 1) / 3;
	   if (POT_PID == PIDROLL)
		   conf.pid[PIDPITCH].I8 = (kp << 1) / 3;
      }
    } else { // Switch TOP = tune D values
      if ((POT_PID != PIDMAG)&&(POT_PID != PIDPOS)){
	   ku = ((constrain(rcData[POT_P],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
	   kp = ku * 6 ;
	   conf.pid[POT_PID].D8 = (kp * 3) >> 3;
	   if (POT_PID == PIDROLL)
		   conf.pid[PIDPITCH].D8 = (kp * 3) >> 3;
      }
    }
#endif
It's not polished and has only been bench tested, but it seems to work like a charm!

If you're wondering why the values computed in the code don't match what's displayed in the GUI, I think it has to do with how the GUI is interpreting the values or how the code is sending the values to the GUI. In the code itself, the PID values (from what I can tell) are not numerically equivalent to what you see in the GUI.

This code:
Code:
int ku = ((constrain(rcData[POT_G],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
int kp = ku + 8; //range: 1.0-3.7
produces values between 1.0 and 3.7 because the values that are presented are divided by 10, they're stored between 10 and 37. If your transmitter goes the full range between 1000 and 2000, then you would actually have values between 0.8 and 3.9. "I" divides the values by 100 or 1000, I can't remember, and the "D" values are presented unmodified...

At least that is what I think. If you look at the MultiWii defaults, it backs up this theory:
Code:
	  #if PID_CONTROLLER == 1
      conf.pid[ROLL].P8     = 33;  conf.pid[ROLL].I8    = 30; conf.pid[ROLL].D8     = 23;
      conf.pid[PITCH].P8    = 33; conf.pid[PITCH].I8    = 30; conf.pid[PITCH].D8    = 23;
      conf.pid[PIDLEVEL].P8 = 90; conf.pid[PIDLEVEL].I8 = 10; conf.pid[PIDLEVEL].D8 = 100;
Jan 21, 2015, 04:10 PM
Whoop the planet!
benedikt's Avatar
Thread OP
I'd just not tune I. So far, I have only see negative effect from changing I, so I just leave it alone..
One knob controlling level-P and the other gyro roll/pitch P/D proportionally works great for me.

When you use your code to switch between the three tuning values, what happens to the "inactive" values? E.g. If you tune P, then switch to D, what happens to P then? Does it go back to default? Does it stay at the last position?
Jan 22, 2015, 11:41 AM
Registered User
I made a few more changes today, and it seems to work. I don't know if I'll actually be adjusting the I-values , but I wanted to have the option.

MultiWii only reads the EEPROM or default values upon start-up. They will not be overwritten once they've been changed. Also, the adjusted values will not be stored in the EEPROM, unless I add code to make that happen. When powered off, the first values loaded on power-on will be values stored in EEPROM -- which means the only way to know what values you set with the pot (exactly, anyway) is to leave it powered on after flying and hook it up to a computer.

One problem with the current code is that when switching the 3-position switch, it will assign the current position of the pot to whatever gets selected by the 3-pos switch along the way. Thus if I start-up, set P, I, and then D, and want to go back and start tuning P, I have to make sure I set the pot in the right place while traveling from the D position to the P position. This is definitely the wrong way to do this, so I think I will be adding something to the code such that the selected position doesn't become active unless it's been selected for more than a second or two (or some number of loop cycles).
Feb 12, 2015, 09:20 AM
avt
avt
Hell Flyer
Quote:
Originally Posted by astroknut
I made a few more changes today, and it seems to work. I don't know if I'll actually be adjusting the I-values , but I wanted to have the option.

MultiWii only reads the EEPROM or default values upon start-up. They will not be overwritten once they've been changed. Also, the adjusted values will not be stored in the EEPROM, unless I add code to make that happen. When powered off, the first values loaded on power-on will be values stored in EEPROM -- which means the only way to know what values you set with the pot (exactly, anyway) is to leave it powered on after flying and hook it up to a computer.

One problem with the current code is that when switching the 3-position switch, it will assign the current position of the pot to whatever gets selected by the 3-pos switch along the way. Thus if I start-up, set P, I, and then D, and want to go back and start tuning P, I have to make sure I set the pot in the right place while traveling from the D position to the P position. This is definitely the wrong way to do this, so I think I will be adding something to the code such that the selected position doesn't become active unless it's been selected for more than a second or two (or some number of loop cycles).
There are a few solutions to this limitation.
On Openpilot flight controllers you assign different pots for different paramteres you want to change.
On Cleanflight the changes are made with switches, not pots. You assign a 3-pos for this task, and define that the middle state does nothing, the highest state increases the value, and the lowest state decreases it.
Then you can add another 3-pos switch that toggles between 3 different parameters that you want to change in-flight. This way there's no need to "remember" the last value of a parameter when switching between parameters.
I've tried both solutions, and both work well. Althogh it's easier for me to use pots.
Feb 13, 2015, 01:25 AM
Closed Account
Has anyone done this with a taranis? I want to have a go with my limited experience on arduino so hopefully someone is able to give a very simple explanation how to do it. Do i simply copy and paste this post into the ardunio sketch?

https://www.rcgroups.com/forums/show...21&postcount=1

Or is the expectation that I should be doing something different from here:

https://www.rcgroups.com/forums/show....php?t=2310813
Mar 11, 2015, 09:54 AM
WarpQuaholic Academy!
nbtran1975's Avatar
Quote:
Originally Posted by benedikt
A while ago, I hacked some MultiWii code together to allow the adjustment of PID values in flight. It works beautifully!
I thought I'd kick off a discussion on this topic to make more people using it and to improve the code over time.

Credit goes to teslahead over on the MultiWii forums, who has done most of the work. I just adjusted it for my needs and trimmed the value ranges for the Pocket Quad.

Here is the exec summary:
  • PID values change the how the flight controller reacts to external forces and to control inputs. "Wrong" PID values can make a multicopter over- or under-react to pilot input, not compensate enough for external input (e.g. wind force) or compensate too much and enter the OoD (Oscillation of Death ).
  • Usually, PID values are programmed into the flight controller from the board manufacturer. In MultiWii, we are (un)-lucky enough (depending on your perspective) to have the ability (and responsibility) to set these values ourselves. This is often enough a frustrating trial and error game.
  • Dynamic PID adjustment allows the pilot to change those values on the fly (!) and adapt the flight characteristics quickly to flight conditions and the task on hand.

E.g. a sporty fly-around requires crisp and sharp values:
https://vimeo.com/78404514

and a sedated camera cruise asks for softer values:
https://vimeo.com/80760688

Lets get cracking:
In the MultiWii standard code, there is the TPA (Throttle PID Attenuation) function. It is supposed to adjust PID values according to throttle input, to stiffen up the aiframe during high acceleration, or soften it during descents. This kicked off the idea for me, because it goes into the right direction, but the implementation was too limited to achieve what I needed.
So I started started off with simply replacing the throttle input with an AUX channel, and adjust TPA manually in flight.
Having achieved that, I was looking for further tuning options, to affect the P, I and D values for gyro and accelerometer separately. Teslaheads code came handy, so I just had to do some c&p to get the basics sorted.

Here is whats needed:
at the very end of void annexCode(), add the following:
Code:
  #if defined(DIAL_TUNING_BG)

    #if defined(POT_G)
    
      int ku = ((constrain(rcData[POT_G],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
      int kp = ku + 8; //range: 1.0-3.7
      conf.pid[PIDROLL].P8 = kp;
      conf.pid[PIDPITCH].P8 = kp;
      
      ku = ((constrain(rcData[POT_G],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
      kp = (ku * 2.7)+22 ;  //range: 10-37
	   //kp = ku * 6 ;  //range: 4-65
           //kp = ku * 10 ; //range: 7-100
      conf.pid[PIDROLL].D8 = (kp * 3) >> 3;
      conf.pid[PIDPITCH].D8 = (kp * 3) >> 3;
    #endif
    
    #if defined(POT_A)
      ku = ((constrain(rcData[POT_A],1000,2000) -1000) << 1) >> 6 ; // * 20/640;
      kp = ku*3 + 8; //range: 1.4-9.5
      //int kp = 3*ku + 16; 
      conf.pid[PIDLEVEL].P8 = kp;
      
    #endif
  #endif
  
  }
At the end of config.h, add the following:
Code:
  #define DIAL_TUNING_BG
  #define POT_G AUX2
  #define POT_A AUX3
Assign 2 AUX channels (ideally pots) to AUX2/3 (or whatever channels you want).
If you flashed this code and connect the board to the MW-GUI, you now twist the knob and when you hit "READ", the current PID values are shown in the GUI.
By changing the "kp=" equations, you can adjust the PID value ranges.
By adding or removing "conf.PID[" lines, you can change what AUX channel is affected what PID values.

I have decided to have channel (AUX2) control Gyro P (1.0 -3.7) and D (10-37) at the same time, and AUX3 control Acc P (1.4-9.5) only.

I hope the above is enough to get others interested in this PID tuning method, kick off some discussions about this, and make it a useful tool for all you propellerheads out there. My programming skills are very basic, but I will try to clarify and answer any questions that come up. My hope that some real code gurus get a sniff of this and will own this thread shortly.
Hi Benedikt, that is very nice.

You said at the very end of void annexCode() Where exactly between which lines??? thx
Mar 13, 2015, 04:54 AM
Whoop the planet!
benedikt's Avatar
Thread OP
A void ends where the next one starts. So just above the next line that starts with "void".
Mar 30, 2015, 12:01 AM
Registered User
Hey Benedikt! Huge fan and I love the idea of PID tuning on the controller. Beats the heck outta going back and forth to the computer if you don't have a bluetooth module. I used your code and got my micro humming. So when setting up my mini this weekend, and after reading up on PID tuning, I decided to take a swing at the code myself. I came across the Ziegler–Nichols method for PID-tuning on a random RCgroup forum and mixed it with your code.

All I values and Level values are set automatically based on the equation I found on wikipedia: http://en.wikipedia.org/wiki/Ziegler...Nichols_method. Low-and-behold, the default MultiWii values for axis PID match the 'no-overshoot' version of the formula. Anyways, here it is:

ZN-Pot Tuning

POT_G changes axis P from 0-11.8ish. I'll explain why: The MultiWii wiki states "for smoth (sic) operation the sum of P axis + P level should stay near the default value : if you decrease P for Roll and pitch axis you can increase P Level". This leads me to believe the real max value for the axis P is 12.3, when the Level P is 0.

POT_A changes axis D from 0-100. This is overkill, as you really need only 0-50 in reality, but it's a start.

Here's the code:
Code:
  #if defined(DIAL_TUNING_BG)
    #if defined(POT_G)
      #if defined(POT_A)
          int ku = 2*(rcData[POT_G]-1077)/3;  //0-11.8ish
          int tu = 15*(rcData[POT_A]-1077)/(ku/12); //Parameterized to ku; this keeps the D value constant as you change P
          //Ziegler–Nichols method: no overshoot from http://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
          int kp = ku/5;
          int ki = 2*kp*100/tu;//<--Tu/100
          int kd = kp/3*tu/100;//<--Tu/100
          //Set axis values
          conf.pid[PIDROLL].P8 = kp;
          conf.pid[PIDPITCH].P8 = kp;
          conf.pid[PIDROLL].I8 = ki;
          conf.pid[PIDPITCH].I8 = ki;
          conf.pid[PIDROLL].D8 = kd;
          conf.pid[PIDPITCH].D8 = kd;
          //Set level values
          kp = 123 - kp; //Level P is just MultiWii's default constant (12.3) minus axis P
          ki = 2*kp/10*100/tu; //Should be the same formula as axis I, but default setting seem to reflect a 1/10th scale
          conf.pid[PIDLEVEL].P8 = kp;
          conf.pid[PIDLEVEL].I8 = ki;
      #endif
    #endif
  #endif
My mini with 6x4 props has super fast wobble and uncontrollable vertical acceleration with out of the box settings; so I turned down the P and still had similar characteristics. Next, I pulled down D. This loosened the vertical and overall flight but gave the "P too low" oscillation. I cranked P back up to about default because I like a responsive feel and BAM! Super-tight handling. I few more tweaks back and forth to lock-it in and custom PID-tuned in a couple minutes. I ended up with a D about half that of default.

P and D should both go in the same direction as they are used to cancel each-other out, and they should only be adjusted slighty away from the defaults, but all this can be found here http://www.multiwii.com/wiki/?title=PID, but with this tuning method you can follow those instructions and skip the I part.

Let me know if anything is blatantly wrong or if you have any suggestions, and please use caution. ENJOY
Apr 20, 2015, 12:34 PM
Registered User
@benedikt
Thank you!! I am using Multiwii 2.3 and worked perfectly, after I found where to put the code.

The file is Multiwii.cpp and the line is around 553

Code:
      #if GPS
        if ( (GPS_speed > GPS_speedMax) ) GPS_speedMax = GPS_speed;
      #endif
    #endif
  }
 **** Add the code here ****
 }

void setup() {
  #if !defined(GPS_PROMINI)
Thank You!


Quick Reply
Message:

Thread Tools