Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copter: run rate loop at full filter rate in its own thread #27029

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
01d205d
Copter: run copter attitude control with separate rate thread
andyp1per Feb 11, 2024
61c47c2
autotest: add rate thread autotest
andyp1per May 22, 2024
482ba22
AP_Vehicle: use update_dynamic_notch() directly in rate loop
tridge Feb 15, 2024
7bd1afc
AP_HAL: allow forcing of trigger_groups()
andyp1per Jun 7, 2024
cfff230
AP_HAL: set HAL_INS_RATE_LOOP in boards
andyp1per Jun 22, 2024
f4ce0aa
AP_HAL_ChibiOS: allow forcing of trigger_groups()
andyp1per Jun 7, 2024
e37a211
AP_HAL_ChibiOS: compile MambaH743v4 at -O2
andyp1per Jul 3, 2024
61308dc
AP_HAL_ChibiOS: ensure dshot rate can be set dynamically
andyp1per Jul 11, 2024
47328c6
scripts: add AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED to build_op…
andyp1per May 22, 2024
0d3e475
waf: add rate loop config abstraction that allows code to be elided o…
andyp1per Aug 7, 2024
e673b70
Copter: correctly set fast rate thread rates
andyp1per Aug 25, 2024
b961a48
AP_InertialSensor: keep a queue of gyro samples for use by the rate t…
andyp1per Feb 11, 2024
353b289
Copter: ensure decimated rates are never 0 in rate thread
andyp1per Oct 5, 2024
26d6de4
AP_InertialSensor: avoid multiple allocations of rate loop buffer
andyp1per Oct 25, 2024
b8d0a00
AP_HAL_ChibiOS: add comments to force_push on rcout
andyp1per Oct 25, 2024
0d346b2
Copter: move RTDT logging to fast path
andyp1per Oct 25, 2024
c57c6d5
Copter: address review comments
andyp1per Nov 10, 2024
90daff6
AP_InertialSensor: address review comments
andyp1per Nov 10, 2024
89bc8ce
AP_HAL_ChibiOS: add cork()/push() check
andyp1per Nov 13, 2024
83b104b
AP_InertialSensor: belt and braces checks
andyp1per Nov 16, 2024
6fefbf0
Copter: allocation failure on rate thread start
andyp1per Nov 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions ArduCopter/Attitude.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@
* Attitude Rate controllers and timing
****************************************************************/

// update rate controllers and output to roll, pitch and yaw actuators
// called at 400hz by default
void Copter::run_rate_controller()
/*
update rate controller when run from main thread (normal operation)
*/
void Copter::run_rate_controller_main()
{
// set attitude and position controller loop time
const float last_loop_time_s = AP::scheduler().get_last_loop_time_s();
motors->set_dt(last_loop_time_s);
attitude_control->set_dt(last_loop_time_s);
pos_control->set_dt(last_loop_time_s);
attitude_control->set_dt(last_loop_time_s);

// run low level rate controllers that only require IMU data
attitude_control->rate_controller_run();
if (!using_rate_thread) {
motors->set_dt(last_loop_time_s);
// only run the rate controller if we are not using the rate thread
attitude_control->rate_controller_run();
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
}
// reset sysid and other temporary inputs
attitude_control->rate_controller_target_reset();
}
Expand Down
40 changes: 33 additions & 7 deletions ArduCopter/Copter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
*/

#include "Copter.h"
#include <AP_InertialSensor/AP_InertialSensor_rate_config.h>

#define FORCE_VERSION_H_INCLUDE
#include "version.h"
Expand Down Expand Up @@ -113,15 +114,15 @@ const AP_Scheduler::Task Copter::scheduler_tasks[] = {
// update INS immediately to get current gyro data populated
FAST_TASK_CLASS(AP_InertialSensor, &copter.ins, update),
// run low level rate controllers that only require IMU data
FAST_TASK(run_rate_controller),
FAST_TASK(run_rate_controller_main),
#if AC_CUSTOMCONTROL_MULTI_ENABLED
FAST_TASK(run_custom_controller),
#endif
#if FRAME_CONFIG == HELI_FRAME
FAST_TASK(heli_update_autorotation),
#endif //HELI_FRAME
// send outputs to the motors library immediately
FAST_TASK(motors_output),
FAST_TASK(motors_output_main),
// run EKF state estimator (expensive)
FAST_TASK(read_AHRS),
#if FRAME_CONFIG == HELI_FRAME
Expand Down Expand Up @@ -259,6 +260,10 @@ const AP_Scheduler::Task Copter::scheduler_tasks[] = {
#if HAL_BUTTON_ENABLED
SCHED_TASK_CLASS(AP_Button, &copter.button, update, 5, 100, 168),
#endif
#if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
// don't delete this, there is an equivalent (virtual) in AP_Vehicle for the non-rate loop case
SCHED_TASK(update_dynamic_notch_at_specified_rate_main, LOOP_RATE, 200, 215),
#endif
};

void Copter::get_scheduler_tasks(const AP_Scheduler::Task *&tasks,
Expand Down Expand Up @@ -570,12 +575,15 @@ void Copter::update_batt_compass(void)
// should be run at loop rate
void Copter::loop_rate_logging()
{
if (should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
if (should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
Log_Write_Attitude();
Log_Write_PIDS(); // only logs if PIDS bitmask is set
if (!using_rate_thread) {
Log_Write_Rate();
Log_Write_PIDS(); // only logs if PIDS bitmask is set
}
}
#if AP_INERTIALSENSOR_HARMONICNOTCH_ENABLED
if (should_log(MASK_LOG_FTN_FAST)) {
if (should_log(MASK_LOG_FTN_FAST) && !using_rate_thread) {
AP::ins().write_notch_log_messages();
}
#endif
Expand All @@ -593,10 +601,15 @@ void Copter::ten_hz_logging_loop()
// log attitude controller data if we're not already logging at the higher rate
if (should_log(MASK_LOG_ATTITUDE_MED) && !should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
Log_Write_Attitude();
if (!using_rate_thread) {
Log_Write_Rate();
}
}
if (!should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
// log at 10Hz if PIDS bitmask is selected, even if no ATT bitmask is selected; logs at looprate if ATT_FAST and PIDS bitmask set
Log_Write_PIDS();
if (!using_rate_thread) {
Log_Write_PIDS();
}
}
// log EKF attitude data always at 10Hz unless ATTITUDE_FAST, then do it in the 25Hz loop
if (!should_log(MASK_LOG_ATTITUDE_FAST)) {
Expand Down Expand Up @@ -741,11 +754,24 @@ void Copter::one_hz_loop()
AP_Notify::flags.flying = !ap.land_complete;

// slowly update the PID notches with the average loop rate
attitude_control->set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
if (!using_rate_thread) {
attitude_control->set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
}
pos_control->get_accel_z_pid().set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
#if AC_CUSTOMCONTROL_MULTI_ENABLED
custom_control.set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
#endif

#if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
// see if we should have a separate rate thread
if (!started_rate_thread && get_fast_rate_type() != FastRateType::FAST_RATE_DISABLED) {
if (hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&Copter::rate_controller_thread, void),
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
"rate",
1536, AP_HAL::Scheduler::PRIORITY_RCOUT, 1)) {
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
started_rate_thread = true;
}
}
#endif
}

void Copter::init_simple_bearing()
Expand Down
39 changes: 37 additions & 2 deletions ArduCopter/Copter.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,17 @@ class Copter : public AP_Vehicle {
RELEASE_GRIPPER_ON_THRUST_LOSS = (1<<2), // 4
REQUIRE_POSITION_FOR_ARMING = (1<<3), // 8
};

// type of fast rate attitude controller in operation
enum class FastRateType : uint8_t {
FAST_RATE_DISABLED = 0,
FAST_RATE_DYNAMIC = 1,
FAST_RATE_FIXED_ARMED = 2,
FAST_RATE_FIXED = 3,
};

FastRateType get_fast_rate_type() const { return FastRateType(g2.att_enable.get()); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if I set a out of range value? Lots of places are checking != FAST_RATE_DISABLED what would a values of -1 result in? Unfortunately we have a presdent that -1 is the same as disabled for lots of params.


// returns true if option is enabled for this vehicle
bool option_is_enabled(FlightOption option) const {
return (g2.flight_options & uint32_t(option)) != 0;
Expand Down Expand Up @@ -726,7 +737,25 @@ class Copter : public AP_Vehicle {
void set_accel_throttle_I_from_pilot_throttle();
void rotate_body_frame_to_NE(float &x, float &y);
uint16_t get_pilot_speed_dn() const;
void run_rate_controller();
void run_rate_controller_main();

// if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
struct RateControllerRates {
uint8_t fast_logging_rate;
uint8_t medium_logging_rate;
uint8_t filter_rate;
uint8_t main_loop_rate;
};

uint8_t calc_gyro_decimation(uint8_t gyro_decimation, uint16_t rate_hz);
void rate_controller_thread();
void rate_controller_filter_update();
void rate_controller_log_update();
void rate_controller_set_rates(uint8_t rate_decimation, RateControllerRates& rates, bool warn_cpu_high);
void enable_fast_rate_loop(uint8_t rate_decimation, RateControllerRates& rates);
void disable_fast_rate_loop(RateControllerRates& rates);
void update_dynamic_notch_at_specified_rate_main();
// endif AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED

#if AC_CUSTOMCONTROL_MULTI_ENABLED
void run_custom_controller() { custom_control.update(); }
Expand Down Expand Up @@ -876,6 +905,7 @@ class Copter : public AP_Vehicle {
// Log.cpp
void Log_Write_Control_Tuning();
void Log_Write_Attitude();
void Log_Write_Rate();
void Log_Write_EKF_POS();
void Log_Write_PIDS();
void Log_Write_Data(LogDataID id, int32_t value);
Expand All @@ -890,6 +920,7 @@ class Copter : public AP_Vehicle {
void Log_Write_SysID_Setup(uint8_t systemID_axis, float waveform_magnitude, float frequency_start, float frequency_stop, float time_fade_in, float time_const_freq, float time_record, float time_fade_out);
void Log_Write_SysID_Data(float waveform_time, float waveform_sample, float waveform_freq, float angle_x, float angle_y, float angle_z, float accel_x, float accel_y, float accel_z);
void Log_Write_Vehicle_Startup_Messages();
void Log_Write_Rate_Thread_Dt(float dt, float dtAvg, float dtMax, float dtMin);
#endif // HAL_LOGGING_ENABLED

// mode.cpp
Expand Down Expand Up @@ -919,7 +950,8 @@ class Copter : public AP_Vehicle {
// motors.cpp
void arm_motors_check();
void auto_disarm_check();
void motors_output();
void motors_output(bool full_push = true);
void motors_output_main();
void lost_vehicle_check();

// navigation.cpp
Expand Down Expand Up @@ -1080,6 +1112,9 @@ class Copter : public AP_Vehicle {
Mode *mode_from_mode_num(const Mode::Number mode);
void exit_mode(Mode *&old_flightmode, Mode *&new_flightmode);

bool started_rate_thread;
bool using_rate_thread;

public:
void failsafe_check(); // failsafe.cpp
};
Expand Down
42 changes: 42 additions & 0 deletions ArduCopter/Log.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Copter.h"
#include <AP_InertialSensor/AP_InertialSensor_rate_config.h>

#if HAL_LOGGING_ENABLED

Expand Down Expand Up @@ -76,6 +77,10 @@ void Copter::Log_Write_Control_Tuning()
void Copter::Log_Write_Attitude()
{
attitude_control->Write_ANG();
}

void Copter::Log_Write_Rate()
{
attitude_control->Write_Rate(*pos_control);
}

Expand Down Expand Up @@ -339,6 +344,16 @@ struct PACKED log_Guided_Attitude_Target {
float climb_rate;
};

// rate thread dt stats
struct PACKED log_Rate_Thread_Dt {
LOG_PACKET_HEADER;
uint64_t time_us;
float dt;
float dtAvg;
float dtMax;
float dtMin;
};

// Write a Guided mode position target
// pos_target is lat, lon, alt OR offset from ekf origin in cm
// terrain should be 0 if pos_target.z is alt-above-ekf-origin, 1 if alt-above-terrain
Expand Down Expand Up @@ -386,6 +401,21 @@ void Copter::Log_Write_Guided_Attitude_Target(ModeGuided::SubMode target_type, f
logger.WriteBlock(&pkt, sizeof(pkt));
}

void Copter::Log_Write_Rate_Thread_Dt(float dt, float dtAvg, float dtMax, float dtMin)
{
#if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
const log_Rate_Thread_Dt pkt {
LOG_PACKET_HEADER_INIT(LOG_RATE_THREAD_DT_MSG),
time_us : AP_HAL::micros64(),
dt : dt,
dtAvg : dtAvg,
dtMax : dtMax,
dtMin : dtMin
};
logger.WriteBlock(&pkt, sizeof(pkt));
#endif
}

// type and unit information can be found in
// libraries/AP_Logger/Logstructure.h; search for "log_Units" for
// units and "Format characters" for field type information
Expand Down Expand Up @@ -527,6 +557,18 @@ const struct LogStructure Copter::log_structure[] = {

{ LOG_GUIDED_ATTITUDE_TARGET_MSG, sizeof(log_Guided_Attitude_Target),
"GUIA", "QBffffffff", "TimeUS,Type,Roll,Pitch,Yaw,RollRt,PitchRt,YawRt,Thrust,ClimbRt", "s-dddkkk-n", "F-000000-0" , true },

// @LoggerMessage: RTDT
// @Description: Attitude controller time deltas
// @Field: TimeUS: Time since system startup
// @Field: dt: current time delta
// @Field: dtAvg: current time delta average
// @Field: dtMax: Max time delta since last log output
// @Field: dtMin: Min time delta since last log output

{ LOG_RATE_THREAD_DT_MSG, sizeof(log_Rate_Thread_Dt),
"RTDT", "Qffff", "TimeUS,dt,dtAvg,dtMax,dtMin", "sssss", "F----" , true },

};

uint8_t Copter::get_num_log_structures() const
Expand Down
17 changes: 17 additions & 0 deletions ArduCopter/Parameters.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Copter.h"

#include <AP_Gripper/AP_Gripper.h>
#include <AP_InertialSensor/AP_InertialSensor_rate_config.h>

/*
This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -1232,6 +1233,22 @@ const AP_Param::GroupInfo ParametersG2::var_info2[] = {
// @User: Advanced
AP_GROUPINFO("FS_EKF_FILT", 8, ParametersG2, fs_ekf_filt_hz, FS_EKF_FILT_DEFAULT),

#if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
// @Param: FSTRATE_ENABLE
// @DisplayName: Enable the fast Rate thread
// @Description: Enable the fast Rate thread. In the default case the fast rate divisor, which controls the update frequency of the thread, is dynamically scaled from FSTRATE_DIV to avoid overrun in the gyro sample buffer and main loop slow-downs. Other values can be selected to fix the divisor to FSTRATE_DIV on arming or always.
// @User: Advanced
// @Values: 0:Disabled,1:Enabled-Dynamic,2:Enabled-FixedWhenArmed,3:Enabled-Fixed
AP_GROUPINFO("FSTRATE_ENABLE", 9, ParametersG2, att_enable, 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you forsee more params here in the future? It would be nice to make this a enable in a little sub tree.


// @Param: FSTRATE_DIV
// @DisplayName: Fast rate thread divisor
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
// @Description: Fast rate thread divisor used to control the maximum fast rate update rate. The actual rate is the gyro rate in Hz divided by this value. This value is scaled depending on the configuration of FSTRATE_ENABLE.
// @User: Advanced
// @Range: 1 10
AP_GROUPINFO("FSTRATE_DIV", 10, ParametersG2, att_decimation, 1),
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
#endif

// ID 62 is reserved for the AP_SUBGROUPEXTENSION

AP_GROUPEND
Expand Down
3 changes: 3 additions & 0 deletions ArduCopter/Parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,9 @@ class ParametersG2 {
AP_Float pldp_range_finder_maximum_m;
AP_Float pldp_delay_s;
AP_Float pldp_descent_speed_ms;

AP_Int8 att_enable;
AP_Int8 att_decimation;
};

extern const AP_Param::Info var_info[];
3 changes: 2 additions & 1 deletion ArduCopter/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ enum LoggingParameters {
LOG_GUIDED_POSITION_TARGET_MSG,
LOG_SYSIDD_MSG,
LOG_SYSIDS_MSG,
LOG_GUIDED_ATTITUDE_TARGET_MSG
LOG_GUIDED_ATTITUDE_TARGET_MSG,
LOG_RATE_THREAD_DT_MSG
};

#define MASK_LOG_ATTITUDE_FAST (1<<0)
Expand Down
1 change: 1 addition & 0 deletions ArduCopter/mode_systemid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ void ModeSystemId::log_data() const

// Full rate logging of attitude, rate and pid loops
copter.Log_Write_Attitude();
copter.Log_Write_Rate();
copter.Log_Write_PIDS();

if (is_poscontrol_axis_type()) {
Expand Down
6 changes: 6 additions & 0 deletions ArduCopter/motor_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ MAV_RESULT Copter::mavlink_motor_test_start(const GCS_MAVLINK &gcs_chan, uint8_t
ap.motor_test = true;

EXPECT_DELAY_MS(3000);

// wait for rate thread to stop running due to motor test
while (using_rate_thread) {
hal.scheduler->delay(1);
}

// enable and arm motors
if (!motors->armed()) {
motors->output_min(); // output lowest possible value to motors
Expand Down
19 changes: 17 additions & 2 deletions ArduCopter/motors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ void Copter::auto_disarm_check()
}

// motors_output - send output to motors library which will adjust and send to ESCs and servos
void Copter::motors_output()
// full_push is true when slower rate updates (e.g. servo output) need to be performed at the main loop rate.
void Copter::motors_output(bool full_push)
{
#if AP_COPTER_ADVANCED_FAILSAFE_ENABLED
// this is to allow the failsafe module to deliberately crash
Expand Down Expand Up @@ -183,7 +184,21 @@ void Copter::motors_output()
}

// push all channels
srv.push();
if (full_push) {
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
// motor output including servos and other updates that need to run at the main loop rate
srv.push();
} else {
// motor output only at main loop rate or faster
hal.rcout->push();
}
}

// motors_output from main thread at main loop rate
void Copter::motors_output_main()
{
if (!using_rate_thread) {
andyp1per marked this conversation as resolved.
Show resolved Hide resolved
motors_output();
}
}

// check for pilot stick input to trigger lost vehicle alarm
Expand Down
Loading
Loading