Apm飞控学习笔记之悬停loiter模式-Cxm

Posted CHENxiaomingming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apm飞控学习笔记之悬停loiter模式-Cxm相关的知识,希望对你有一定的参考价值。

文章汇集

PX4/APM/飞控的学习笔记前言-Cxm_CHENxiaomingming的博客-CSDN博客_apm和px4哪个好


前言

        时隔一段时间又开始琢磨APM飞控了,在上一篇中写了姿态控制,经过实机测试使用的是HC-SR04超声波效果并不是特别理想,并且在外部数据控制无人机姿态的情况下虽然经过了飞控的PID但是效果依然好(可能只是我的超声波算法不太行),所以就展开了对Apm位置控制的了解,我先从官网查询了一下位置控制发现官网介绍的很是简短 如下:

所以打算对定点模式(loiter)和自动模式(AUTO)入手。

70K的代码量真的多而且笔记手法越写感觉越像记流水。


目录

目录

前言

定点模式(loiter)

init部分,当模式正常进入到loiter中时

        run部分*


定点模式(loiter)

        在ArduCopter\\mode.h文件下我们可以找到

 LOITER =        5,  // automatic horizontal acceleration with automatic throttle

大概意思就是利用气压计和GPS进行辅助定点的模式,在ArduCopter\\mode_loiter.cpp的内容就是模式所运行的代码,如下:

#include "Copter.h"

#if MODE_LOITER_ENABLED == ENABLED

/*
 * Init and run calls for loiter flight mode
 */

// loiter_init - initialise loiter controller
bool ModeLoiter::init(bool ignore_checks)

    if (!copter.failsafe.radio) 
        float target_roll, target_pitch;
        // apply SIMPLE mode transform to pilot inputs
        update_simple_mode();

        // convert pilot input to lean angles
        get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());

        // process pilot's roll and pitch input
        loiter_nav->set_pilot_desired_acceleration(target_roll, target_pitch, G_Dt);
     else 
        // clear out pilot desired acceleration in case radio failsafe event occurs and we do not switch to RTL for some reason
        loiter_nav->clear_pilot_desired_acceleration();
    
    loiter_nav->init_target();

    // initialise position and desired velocity
    //期望位置和期望速度
    if (!pos_control->is_active_z()) 
        pos_control->set_alt_target_to_current_alt();
        pos_control->set_desired_velocity_z(inertial_nav.get_velocity_z());
    

    return true;


#if PRECISION_LANDING == ENABLED
bool ModeLoiter::do_precision_loiter()

    if (!_precision_loiter_enabled) 
        return false;
    
    if (copter.ap.land_complete_maybe) 
        return false;        // don't move on the ground
    
    // if the pilot *really* wants to move the vehicle, let them....
    if (loiter_nav->get_pilot_desired_acceleration().length() > 50.0f) 
        return false;
    
    if (!copter.precland.target_acquired()) 
        return false; // we don't have a good vector
    
    return true;


void ModeLoiter::precision_loiter_xy()

    loiter_nav->clear_pilot_desired_acceleration();
    Vector2f target_pos, target_vel_rel;
    if (!copter.precland.get_target_position_cm(target_pos)) 
        target_pos.x = inertial_nav.get_position().x;
        target_pos.y = inertial_nav.get_position().y;
    
    if (!copter.precland.get_target_velocity_relative_cms(target_vel_rel)) 
        target_vel_rel.x = -inertial_nav.get_velocity().x;
        target_vel_rel.y = -inertial_nav.get_velocity().y;
    
    pos_control->set_xy_target(target_pos.x, target_pos.y);
    pos_control->override_vehicle_velocity_xy(-target_vel_rel);

#endif

// loiter_run - runs the loiter controller
// should be called at 100hz or more
void ModeLoiter::run()

    float target_roll, target_pitch;
    float target_yaw_rate = 0.0f;
    float target_climb_rate = 0.0f;
    float takeoff_climb_rate = 0.0f;

    // initialize vertical speed and acceleration
    pos_control->set_max_speed_z(-get_pilot_speed_dn(), g.pilot_speed_up);
    pos_control->set_max_accel_z(g.pilot_accel_z);

    // process pilot inputs unless we are in radio failsafe
    if (!copter.failsafe.radio) 
        // apply SIMPLE mode transform to pilot inputs
        update_simple_mode();

        // convert pilot input to lean angles
        get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());

        // process pilot's roll and pitch input
        loiter_nav->set_pilot_desired_acceleration(target_roll, target_pitch, G_Dt);

        // get pilot's desired yaw rate
        target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());

        // get pilot desired climb rate
        target_climb_rate = get_pilot_desired_climb_rate(channel_throttle->get_control_in());
        target_climb_rate = constrain_float(target_climb_rate, -get_pilot_speed_dn(), g.pilot_speed_up);
     else 
        // clear out pilot desired acceleration in case radio failsafe event occurs and we do not switch to RTL for some reason
        loiter_nav->clear_pilot_desired_acceleration();
    

    // relax loiter target if we might be landed
    if (copter.ap.land_complete_maybe) 
        loiter_nav->soften_for_landing();
    

    // Loiter State Machine Determination 
    AltHoldModeState loiter_state = get_alt_hold_state(target_climb_rate);

    // Loiter State Machine
    switch (loiter_state) 

    case AltHold_MotorStopped:
        attitude_control->reset_rate_controller_I_terms();
        attitude_control->set_yaw_target_to_current_heading();
        pos_control->relax_alt_hold_controllers(0.0f);   // forces throttle output to go to zero
        loiter_nav->init_target();
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);
        pos_control->update_z_controller();
        break;

    case AltHold_Takeoff:
        // initiate take-off
        if (!takeoff.running()) 
            takeoff.start(constrain_float(g.pilot_takeoff_alt,0.0f,1000.0f));
        

        // get takeoff adjusted pilot and takeoff climb rates
        takeoff.get_climb_rates(target_climb_rate, takeoff_climb_rate);

        // get avoidance adjusted climb rate
        target_climb_rate = get_avoidance_adjusted_climbrate(target_climb_rate);

        // run loiter controller
        loiter_nav->update();

        // call attitude controller
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);

        // update altitude target and call position controller
        pos_control->set_alt_target_from_climb_rate_ff(target_climb_rate, G_Dt, false);
        pos_control->add_takeoff_climb_rate(takeoff_climb_rate, G_Dt);
        pos_control->update_z_controller();
        break;

    case AltHold_Landed_Ground_Idle:
        attitude_control->set_yaw_target_to_current_heading();
        // FALLTHROUGH

    case AltHold_Landed_Pre_Takeoff:
        attitude_control->reset_rate_controller_I_terms_smoothly();
        loiter_nav->init_target();
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(0.0f, 0.0f, 0.0f);
        pos_control->relax_alt_hold_controllers(0.0f);   // forces throttle output to go to zero
        pos_control->update_z_controller();
        break;

    case AltHold_Flying:
        // set motors to full range
        motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);

#if PRECISION_LANDING == ENABLED
        if (do_precision_loiter()) 
            precision_loiter_xy();
        
#endif

        // run loiter controller
        loiter_nav->update();

        // call attitude controller
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);

        // adjust climb rate using rangefinder
        target_climb_rate = copter.surface_tracking.adjust_climb_rate(target_climb_rate);

        // get avoidance adjusted climb rate
        target_climb_rate = get_avoidance_adjusted_climbrate(target_climb_rate);

        pos_control->set_alt_target_from_climb_rate_ff(target_climb_rate, G_Dt, false);
        pos_control->update_z_controller();
        break;
    


uint32_t ModeLoiter::wp_distance() const

    return loiter_nav->get_distance_to_target();


int32_t ModeLoiter::wp_bearing() const

    return loiter_nav->get_bearing_to_target();


#endif

       大致分为两个部分,init都是为初始化的操作函数,run则是控制操作函数

init部分,当模式正常进入到loiter中时

bool ModeLoiter::init(bool ignore_checks)

    if (!copter.failsafe.radio) 
        float target_roll, target_pitch;
        // apply SIMPLE mode transform to pilot inputs
        update_simple_mode();

        // convert pilot input to lean angles
        get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());

        // process pilot's roll and pitch input
        设置导航所需的中心度//dt 加速度应该是自上次调用此函数以来的时间(以秒为单位)
        loiter_nav->set_pilot_desired_acceleration(target_roll, target_pitch, G_Dt);
     else 
        // clear out pilot desired acceleration in case radio failsafe event occurs and we do not switch to RTL for some reason
        //清除飞行员理想的加速,以防万一无线电故障事件发生,我们不切换到 rtl 的某些原因
        loiter_nav->clear_pilot_desired_acceleration();
    
    //初始化的位置和前馈速度从目前的位置和速度
    loiter_nav->init_target();

    // initialise position and desired velocity
    //期望位置和期望速度
    if (!pos_control->is_active_z()) 
        pos_control->set_alt_target_to_current_alt();
        pos_control->set_desired_velocity_z(inertial_nav.get_velocity_z());
    

    return true;

1.1驾驶员期望角度获取

首先我们来看一下get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());

这个是获取遥控器的数据并转换成角度跳转到ArduCopter\\mode.cpp中

void Mode::get_pilot_desired_lean_angles(float &roll_out, float &pitch_out, float angle_max, float angle_limit) const

    // throttle failsafe check
    if (copter.failsafe.radio || !copter.ap.rc_receiver_present) 
        roll_out = 0;
        pitch_out = 0;
        return;
    
    // fetch roll and pitch inputs
    roll_out = channel_roll->get_control_in();
    pitch_out = channel_pitch->get_control_in();

	// limit max lean angle
    angle_limit = constrain_float(angle_limit, 1000.0f, angle_max);

    // scale roll and pitch inputs to ANGLE_MAX parameter range
    float scaler = angle_max/(float)ROLL_PITCH_YAW_INPUT_MAX;
    roll_out *= scaler;
    pitch_out *= scaler;

    // do circular limit
    float total_in = norm(pitch_out, roll_out);
    if (total_in > angle_limit) 
        float ratio = angle_limit / total_in;
        roll_out *= ratio;
        pitch_out *= ratio;
    

    // do lateral tilt to euler roll conversion
    roll_out = (18000/M_PI) * atanf(cosf(pitch_out*(M_PI/18000))*tanf(roll_out*(M_PI/18000)));

    // roll_out and pitch_out are returned

直接看是这么获取的

    roll_out = channel_roll->get_control_in();
    pitch_out = channel_pitch->get_control_in();

        run部分*

void ModeLoiter::run()

    float target_roll, target_pitch;
    float target_yaw_rate = 0.0f;
    float target_climb_rate = 0.0f;
    float takeoff_climb_rate = 0.0f;

    // initialize vertical speed and acceleration
    //初始化垂直速度和加速度
    pos_control->set_max_speed_z(-get_pilot_speed_dn(), g.pilot_speed_up);
    pos_control->set_max_accel_z(g.pilot_accel_z);

    // process pilot inputs unless we are in radio failsafe
    if (!copter.failsafe.radio) 
        // apply SIMPLE mode transform to pilot inputs
        update_simple_mode();

        // convert pilot input to lean angles
        // RC输入转换成角度
        get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());

        // process pilot's roll and pitch input
        //处理飞行员的横摇和俯仰输入
        loiter_nav->set_pilot_desired_acceleration(target_roll, target_pitch, G_Dt);

        // get pilot's desired yaw rate
        //获取RC偏航
        target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());

        // get pilot desired climb rate
        //获取RC爬升速度
        target_climb_rate = get_pilot_desired_climb_rate(channel_throttle->get_control_in());
        target_climb_rate = constrain_float(target_climb_rate, -get_pilot_speed_dn(), g.pilot_speed_up);
     else 
        // clear out pilot desired acceleration in case radio failsafe event occurs and we do not switch to RTL for some reason
        loiter_nav->clear_pilot_desired_acceleration();
    

    // relax loiter target if we might be landed
    if (copter.ap.land_complete_maybe) 
        loiter_nav->soften_for_landing();
    

    // Loiter State Machine Determination 
    AltHoldModeState loiter_state = get_alt_hold_state(target_climb_rate);

    // Loiter State Machine
    switch (loiter_state) 

    case AltHold_MotorStopped:
        attitude_control->reset_rate_controller_I_terms();
        attitude_control->set_yaw_target_to_current_heading();
        pos_control->relax_alt_hold_controllers(0.0f);   // forces throttle output to go to zero
        loiter_nav->init_target();
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);
        pos_control->update_z_controller();
        break;

    case AltHold_Takeoff:
        // initiate take-off
        if (!takeoff.running()) 
            takeoff.start(constrain_float(g.pilot_takeoff_alt,0.0f,1000.0f));
        

        // get takeoff adjusted pilot and takeoff climb rates
        takeoff.get_climb_rates(target_climb_rate, takeoff_climb_rate);

        // get avoidance adjusted climb rate
        target_climb_rate = get_avoidance_adjusted_climbrate(target_climb_rate);

        // run loiter controller
        loiter_nav->update();

        // call attitude controller
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);

        // update altitude target and call position controller
        pos_control->set_alt_target_from_climb_rate_ff(target_climb_rate, G_Dt, false);
        pos_control->add_takeoff_climb_rate(takeoff_climb_rate, G_Dt);
        pos_control->update_z_controller();
        break;

    case AltHold_Landed_Ground_Idle:
        attitude_control->set_yaw_target_to_current_heading();
        // FALLTHROUGH

    case AltHold_Landed_Pre_Takeoff:
        attitude_control->reset_rate_controller_I_terms_smoothly();
        loiter_nav->init_target();
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(0.0f, 0.0f, 0.0f);
        pos_control->relax_alt_hold_controllers(0.0f);   // forces throttle output to go to zero
        pos_control->update_z_controller();
        break;

    case AltHold_Flying:
        // set motors to full range
        motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);

#if PRECISION_LANDING == ENABLED
        if (do_precision_loiter()) 
            precision_loiter_xy();
        
#endif

        // run loiter controller
        loiter_nav->update();

        // call attitude controller
        attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);

        // adjust climb rate using rangefinder
        target_climb_rate = copter.surface_tracking.adjust_climb_rate(target_climb_rate);

        // get avoidance adjusted climb rate
        target_climb_rate = get_avoidance_adjusted_climbrate(target_climb_rate);

        pos_control->set_alt_target_from_climb_rate_ff(target_climb_rate, G_Dt, false);
        pos_control->update_z_controller();
        break;
    

其中AltHoldModeState loiter_state = get_alt_hold_state(target_climb_rate);是他的飞行模式判断

在ArduCopter\\mode.h中可以找到对应的模式,这些模式都不是正常使用情况下的模式而是以下的代码。

    // Alt_Hold based flight mode states used in Alt_Hold, Loiter, and Sport
    enum AltHoldModeState 
        AltHold_MotorStopped,        //大概就是初始化数据停止的意思
        AltHold_Takeoff,             //起飞的状态
        AltHold_Landed_Ground_Idle,
        AltHold_Landed_Pre_Takeoff,
        AltHold_Flying
    ;
    AltHoldModeState get_alt_hold_state(float target_climb_rate_cms);

1.1运行位置控制器 loiter_nav->update(); 在libraries\\AC_WPNav\\AC_Loiter.cpp中

/// run the loiter controller
void AC_Loiter::update()

    // calculate dt
    float dt = _pos_control.time_since_last_xy_update();
    if (dt >= 0.2f) 
        dt = 0.0f;
    

    // initialise pos controller speed and acceleration
    _pos_control.set_max_speed_xy(_speed_cms);
    _pos_control.set_max_accel_xy(_accel_cmss);

    calc_desired_velocity(dt);
    //运行水平位置控制器
    _pos_control.update_xy_controller();

1.2. 初始化位置控制器的速度和加速度:

    // initialise pos controller speed and acceleration
    _pos_control.set_max_speed_xy(_speed_cms);
    _pos_control.set_max_accel_xy(_accel_cmss);

 1.3. 更新最新的期望速度和前馈发送到位置控制器中:

calc_desired_velocity(dt);

1.4.运行水平控制器

_pos_control.update_xy_controller();

这里可以参考

Apm飞控学习笔记-AC_PosControl位置控制-Cxm_CHENxiaomingming的博客-CSDN博客在上一篇的Copter.cpp中运行的位置控制器的介绍,这篇相对较多较为复杂而且代码量大所以分段解释在libraries\\AC_AttitudeControl\\AC_PosControl.cpp:下首先是水平位置控制器void AC_PosControl::run_xy_controller(float dt)EKF选择 AP::ahrs_navekf().getEkfControlLimits(ekfGndSpdLimit, ekfNavVelGainScaler);这个估https://blog.csdn.net/chen_taifu/article/details/124610904

1.5.运行姿态控制器

 attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(loiter_nav->get_roll(), loiter_nav->get_pitch(), target_yaw_rate);

loiter_nav->get_roll(), loiter_nav->get_pitch() 传参是通过水平控制器通过EKF运行计算出来的参数

target_yaw_rate则是飞行员控制的航向,也就是偏航

1.6后面高度的控制了

// 测距仪调整爬升高度

        target_climb_rate = copter.surface_tracking.adjust_climb_rate(target_climb_rate);

        // get avoidance adjusted climb rate

        //调整上升速度

        target_climb_rate = get_avoidance_adjusted_climbrate(target_climb_rate);

        pos_control->set_alt_target_from_climb_rate_ff(target_climb_rate, G_Dt, false);

        //这将运行 z 轴位置控制 PID 循环并将低级油门级别发送到 AP_Motors 库

        pos_control->update_z_controller();

        break;

要注意的是AltHold_Flying是正在飞行中的标志位

END

以上是关于Apm飞控学习笔记之悬停loiter模式-Cxm的主要内容,如果未能解决你的问题,请参考以下文章

Apm飞控学习笔记之悬停loiter模式-Cxm

Apm飞控学习笔记之添加我的飞行模式-Cxm

Apm飞控学习笔记之添加我的飞行模式-Cxm

Apm飞控学习笔记之如何添加自己的功能-Cxm

Apm飞控学习笔记之添加我的设备或单片机-Cxm

Apm飞控学习笔记之添加我的设备或单片机-Cxm