Unlocking the Potential of Faster Attitude Rates in Copter Control

Unlocking the Potential of Faster Attitude Rates in Copter Control

For the past few weeks, I’ve been diving into the world of fast attitude rates. This journey started somewhat by chance. Initially, I thought Leonard would tackle the challenge, but, when I discussed it with Tridge, he surprised me by saying it was more his domain. He quickly put together a thread-based rate loop, which worked, but not sufficiently well for there to be any discernible advantage - when I pushed it harder, things started falling apart. Tridge was somewhat sceptical about its potential, but I decided to take on the challenge and see if I could push it further!

After fixing several issues, I had a breakthrough during auto-tuning. The responses were significantly snappier, giving me the confidence to continue. Let me explain what’s happening.

Imagine you’re flying a copter. Its control system is based on a PID (Proportional-Integral-Derivative) controller. When you command a roll to the right, say at 90 degrees per second, the copter’s current rate is compared to this target. The PID controller calculates the error – the difference between the target and actual rate.

  • P (Proportional): Applies input proportional to the error. For example, with a P value of 1, it applies a rate of 90 degrees per second if the error is 90 degrees per second.
  • D (Derivative): Prevents overshoot by responding to the rate of error change. Faster changes in error increase the D response, countering the P response to prevent overshooting.

All this control takes time. If the loop rate is 400 Hz, it takes a minimum of 2.5 milliseconds to detect an error and respond. While this is fast for humans, it’s a significant delay when handling disturbances like prop wash or high-rate oscillations. In theory, running the PID controllers faster can improve control. Betaflight, for instance, normally runs the PID controllers at at least 4kHz.

ArduCopter’s main loop can run up to 800Hz, maybe 1000Hz if you are lucky, improving control for smaller copters. However, running it faster is limited by the computational expense of the EKF (Extended Kalman Filter) maths. Tridge’s innovation was to separate the rate updates into a different thread, allowing them to run as fast as needed.

Ideally, rate updates should match the gyro data rate. On my test copter, the gyros run at 4kHz. By running the rate loop at 4 kHz, we reduce the detection time from 2.5 milliseconds to 250 microseconds, enhancing the copter’s responsiveness to disturbances and inputs. This tighter control allows for more aggressive tuning.

Oscillation happens when the PID controller overcompensates. With faster rates, we can apply more P without causing oscillation because D can respond quickly enough to moderate the P response. On my test copter, tuning with a 4kHz rate loop has allowed me to double the PIDs, which is a very substantial improvemen!

This change is a game-changer and is likely to be included in version 4.6. While it works beautifully on H7 boards, F4 boards might struggle due to the computational load. On an H7 running at 4kHz, the rate loop consumes 25% of the CPU, a significant chunk. F4 boards might manage at 1kHz, but higher rates could be challenging.

Configuration

There are only two new settings for enabling fast rate attitude, but these have an effect on several other settings:

  • FSTRATE_ENABLE
    • 1 - enable dynamic fast rate, on high CPU load (as determined by either the main loop being slow or the gyro sample queue filling up) the rate will be reduced to an integer divisor of the gyro rate until the CPU stabilises. This is the safest way of trying the support.
    • 2 - enable dynamic fast rate, but fix to the requested rate on arming. This allows un-armed operations such as log download to proceed effectively. Note that you must be sure that you have sufficient CPU to enable this option or control can be compromised.
    • 3 - enable fixed fast rate. This is useful for testing
  • FSTRATE_DIV - this defaults to 1 and represents the maximum fast rate gyro divisor. So a value of 2 will yield a rate loop of gyro rate / 2. This allows a fixed fast rate that is lower than the gyro rate. This parameter is dynamic and can be modified in-flight.

So the easiest way to try this is set FSTRATE_ENABLE = 1. If your flight controller is struggling it will reduce the attitude loop rate until normality is restored. For fixed rates I do not recommend trying this until you have seen reasonable performance with dynamic rates. One way to gain more CPU is to switch off additional IMUs using INS_ENABLE_MASK another way is to reduce INS_GYRO_RATE. The main CPU load is from the INS and attitude threads.

When the fast attitude loop is enable, several other settings are affected:

  • SERVO_DSHOT_RATE - this represents a multiplier of the main loop rate to output to the motors. When the fast rate loop is enabled this is normally set to 1, however if the calculated rate will not exceed the gyro rate, higher values are allowed. For instance if INS_GYRO_RATE = 2 and FSTRATE_DIV = 4 then values of SERVO_DSHOT_RATE up to 4 are allowed.
  • Fast attitude and PID logging in LOG_BITMASK - setting these bits usually logs at the main loop rate, however if fast attitude is enabled these will be logged at the minimum of the fast attitude rate and 1kHz
  • SCHED_LOOP_RATE - since all the heavy lifting of attitude control is being done in a separate thread, SCHED_LOOP_RATE can be run at normal values - for instance 400Hz or even less.

As part of this support I have written a lua script that allows you to switch in-flight between two sets of rates and tunes - switch_rates.lua. This can be packaged in the firmware of flash log based flight controllers, so I will include this support in firmware builds that I do. Set RTSW_ENABLE = 1 and RCx_OPTION = 300 for the RC channel that you want to use to switch between rates. The following parameters will be switched by the RC function.

ATC_ACCEL_P_MAX
ATC_ACCEL_R_MAX
ATC_ACCEL_Y_MAX
ATC_ANG_PIT_P
ATC_ANG_RLL_P
ATC_ANG_YAW_P
ATC_RAT_PIT_P
ATC_RAT_PIT_I
ATC_RAT_PIT_D
ATC_RAT_PIT_D_FF
ATC_RAT_PIT_FLTD
ATC_RAT_RLL_P
ATC_RAT_RLL_I
ATC_RAT_RLL_D
ATC_RAT_RLL_D_FF
ATC_RAT_RLL_FLTD
ATC_RAT_YAW_P
ATC_RAT_YAW_I
ATC_RAT_YAW_D
ATC_RAT_YAW_D_FF
ATC_RAT_YAW_FLTD
ATC_THR_G_BOOST
ACRO_RP_RATE_TC
ACRO_Y_RATE_TC
FSTRATE_ENABLE
FSTRATE_DIV
MOT_SPIN_MIN
MOT_SPIN_MAX
MOT_THST_EXPO
SERVO_DSHOT_RATE

Initially you can just load a standard tune into both positions, but after you have done this enable the fast rate attitude in one and try setting up a different tune. Note that it is not possible to change SCHED_LOOP_RATE dynamically so if you want a attitude rate different to SCHED_LOOP_RATE you will need to use FSTRATE_DIV instead.

Let me know in the comments what flight controllers you want to try this on and I will do builds.

PR is here:

Firmware is available here:

https://www.dropbox.com/scl/fo/1qboeg55r4el70vtp6hi3/AMNFpcbC_qZR095HU8aw7EU?rlkey=2ua7kzju1tptrschesivgvwrd&dl=0

Current builds:

  • MambaH743v4 (compiled with -O2)
  • MatekH743-bdshot (running at 480mHz)
  • Pixhawk6X
  • Pixhawk6C
  • CUAVv5Nano

I have done a stats version of each of the builds so that people can inspect the CPU load. I do not recommend you fly with this version. CPU profile information can be seen via @SYS/threads.txt in mavproxy or Mission Planner

Lua rate switching applet is here - ardupilot/libraries/AP_Scripting/applets/switch_rates.lua at pr-fast-rate-thread · andyp1per/ardupilot · GitHub and docs are here - ardupilot/libraries/AP_Scripting/applets/switch_rates.md at pr-fast-rate-thread · andyp1per/ardupilot · GitHub

17 Likes

Hi @andyp1per ,

really interested in testing this on a trad-heli FPV platform - Holybro Pixhawk 6C mini.

…….

Matek H743 please.

Finally the F4 can fade away with 4.6..,

When testing on a Pixhawk6X I noticed some oddities that I will need to get to the bottom of - might be something to do with the CPU overhead of the IOMCU. Am away for a few days so will be next week.

2 Likes

Link in OP together with stats builds

Andy,
This is very interesting stuff. Did you do any comparison of the responses? I would be interested in seeing the before and after frequency responses for pitch or roll axes. I would probably use the rate target as the input. You may gather data for both rate controllers using the same gains and then with the high rate one optimally tuned. Just a thought.

1 Like

Hi Bill, I have eyeballed the responses by looking at logs in autotune - they are quite different. I have not got any more scientific than that. What would be the easiest way to measure the frequency response?

Conduct a sysid using sysid_axis 1 or 2 for pitch or roll. Set the log_bitmask to have both fast attitude and med attitude checked so we get 400 hz logging. Set the min freq to .5 hz and max freq to 20hz. I’m not sure what the bandwidth of your small aircraft is.

4 Likes

I’d be happy to do the analysis. So you can just share the data on a cloud Drive.

1 Like

Is it possible to have mode specific rate (like for acro only) and a “normal” rate at the same time, just like the lua switching but baked into the firmware. So we can use high pid rate when attitude responsiveness is prioritized and use low pid rate when EKF estimation is prioritized.

Yes, there is a lua script from tridge that does just that.

Yeah that’s a nice idea. The issue is that it requires switching a lot of parameters which is quite heavy on flash, so I’m not sure this would be accepted as anything other than a LUA script.

Ahhh, I made a mistake. What I mean is mode specific rate then rate specific pid. I was thinking that these parameters could coexist and have another parameter decides which mode uses which combo, just like acro_option could enable airmode and rate loop only control for acro mode.

It’s possible, but the tune will change with the faster rate and that is what requires the parameter updates.

But I will see if I can add it to my script.

Pixhawk6X checked out ok, to be safe switch off one or two of the IMUs via INS_ENABLE_MASK, but its not horrendous. Doing the builds of Pixhawk6X-bdshot and Pixhawk6C-bdshot now …

1 Like

Tried on my 5 inch, H7 with dynamic notch enabled. It looks like H7 is maxed out at 4k, tried 8k with dynamic rate and after arming it would drop to as low as 100hz, but when setting gyro at 4k and running at dynamic rate it never says anything, so I assume it is stably running at 4k.
I’m not a great pilot so I didn’t feel so much difference other than that the newly built 5 inch flew much better than my 7inch. Will let my friend to try it and see his reaction next week.
FYI, my pid for roll increased about 40% from 0.055 → 0.077 for p and 33% for pitch from 0.075 → 0.101 for p. Previously running at 800hz, both are from autotune.

1 Like

Thanks for testing! What flight controller?

Matek H743 slim and airbot am32 4in1 esc running at 6s with AOS SuperNova 1980kv

How about a dedicated settings bank for fast rate controller loop?

May as well do dual PIDs at that point which has been discussed but the answer is always “use scripting”