/*
本程序是免费软件:你可以根据免费软件基金会发布的GNU通用公共许
可证的条款,即许可证的第3版,或(看你的选择)任何更高的版本,重新发布和/或修改它。
本程序的发布是希望它能有用,但没有任何保证;甚至没有明确的质保
或第三方保证。 更多细节请参见GNU通用公共许可证。
你应该已经收到了一份与本程序一起的GNU通用公共许可证的副本。
如果没有,请参阅
*/
#include "Plane.h"
#define SCHED_TASK(func, rate_hz, max_time_micros, priority) SCHED_TASK_CLASS(Plane, &plane, func, rate_hz, max_time_micros, priority)
#define FAST_TASK(func) FAST_TASK_CLASS(Plane, &plane, func)
/*
参数表 - 所有常规任务都应列在这里。
这个表中的所有条目按优先级排序。
这个表与嵌套于每个子程序中的表交错排列,以确定任务运行的顺序。
提供方便的方法SCHED_TASK和SCHED_TASK_CLASS来建立这个结构中的条目:
SCHED_TASK 函数结构和参数意义:
- 要调用静态函数的名称
- 调用该函数的速率(赫兹)。
- 该函数运行的预期时间(微秒)。
- 优先级(0到255,数字越小意味着优先级越高)。
SCHED_TASK_CLASS 函数结构和参数意义:
- 要调用的方法的类名
- 调用该方法的实例
- 要在该实例上调用的方法
- 调用该方法的速率(赫兹)。
- 该方法运行的预期时间(微秒)。
- 优先级(0到255,数字越小意味着优先级越高)
*/
const AP_Scheduler::Task Plane::scheduler_tasks[] = {
// FAST_TASK条目在每个循环上运行,即使这意味着该循环允许超过了其分配的时间
FAST_TASK(ahrs_update),
FAST_TASK(update_control_mode),
FAST_TASK(stabilize),
FAST_TASK(set_servos),
// 要调用静态函数的名称 调用该函数的速率(Hz) 函数运行的预期时间(微秒) 优先级
SCHED_TASK(read_radio, 50, 100, 6),
SCHED_TASK(check_short_failsafe, 50, 100, 9),
SCHED_TASK(update_speed_height, 50, 200, 12),
SCHED_TASK(update_throttle_hover, 100, 90, 24),
SCHED_TASK(read_control_switch, 7, 100, 27),
SCHED_TASK(update_GPS_50Hz, 50, 300, 30),
SCHED_TASK(update_GPS_10Hz, 10, 400, 33),
SCHED_TASK(navigate, 10, 150, 36),
SCHED_TASK(update_compass, 10, 200, 39),
SCHED_TASK(calc_airspeed_errors, 10, 100, 42),
SCHED_TASK(update_alt, 10, 200, 45),
SCHED_TASK(adjust_altitude_target, 10, 200, 48),
#if ADVANCED_FAILSAFE == ENABLED
SCHED_TASK(afs_fs_check, 10, 100, 51),
#endif
SCHED_TASK(ekf_check, 10, 75, 54),
SCHED_TASK_CLASS(GCS, (GCS*)&plane._gcs, update_receive, 300, 500, 57),
SCHED_TASK_CLASS(GCS, (GCS*)&plane._gcs, update_send, 300, 750, 60),
SCHED_TASK_CLASS(AP_ServoRelayEvents, &plane.ServoRelayEvents, update_events, 50, 150, 63),
SCHED_TASK_CLASS(AP_BattMonitor, &plane.battery, read, 10, 300, 66),
SCHED_TASK_CLASS(AP_Baro, &plane.barometer, accumulate, 50, 150, 69),
SCHED_TASK_CLASS(AP_Notify, &plane.notify, update, 50, 300, 72),
SCHED_TASK(read_rangefinder, 50, 100, 78),
#if AP_ICENGINE_ENABLED
SCHED_TASK_CLASS(AP_ICEngine, &plane.g2.ice_control, update, 10, 100, 81),
#endif
#if AP_OPTICALFLOW_ENABLED
SCHED_TASK_CLASS(AP_OpticalFlow, &plane.optflow, update, 50, 50, 87),
#endif
SCHED_TASK(one_second_loop, 1, 400, 90),
SCHED_TASK(three_hz_loop, 3, 75, 93),
SCHED_TASK(check_long_failsafe, 3, 400, 96),
SCHED_TASK_CLASS(AP_RPM, &plane.rpm_sensor, update, 10, 100, 99),
#if AP_AIRSPEED_AUTOCAL_ENABLE
SCHED_TASK(airspeed_ratio_update, 1, 100, 102),
#endif // AP_AIRSPEED_AUTOCAL_ENABLE
#if HAL_MOUNT_ENABLED
SCHED_TASK_CLASS(AP_Mount, &plane.camera_mount, update, 50, 100, 105),
#endif // HAL_MOUNT_ENABLED
#if CAMERA == ENABLED
SCHED_TASK_CLASS(AP_Camera, &plane.camera, update, 50, 100, 108),
#endif // CAMERA == ENABLED
SCHED_TASK_CLASS(AP_Scheduler, &plane.scheduler, update_logging, 0.2, 100, 111),
SCHED_TASK(compass_save, 0.1, 200, 114),
SCHED_TASK(Log_Write_FullRate, 400, 300, 117),
SCHED_TASK(update_logging10, 10, 300, 120),
SCHED_TASK(update_logging25, 25, 300, 123),
#if HAL_SOARING_ENABLED
SCHED_TASK(update_soaring, 50, 400, 126),
#endif
SCHED_TASK(parachute_check, 10, 200, 129),
#if AP_TERRAIN_AVAILABLE
SCHED_TASK_CLASS(AP_Terrain, &plane.terrain, update, 10, 200, 132),
#endif // AP_TERRAIN_AVAILABLE
SCHED_TASK(update_is_flying_5Hz, 5, 100, 135),
#if LOGGING_ENABLED == ENABLED
SCHED_TASK_CLASS(AP_Logger, &plane.logger, periodic_tasks, 50, 400, 138),
#endif
SCHED_TASK_CLASS(AP_InertialSensor, &plane.ins, periodic, 50, 50, 141),
#if HAL_ADSB_ENABLED
SCHED_TASK(avoidance_adsb_update, 10, 100, 144),
#endif
SCHED_TASK_CLASS(RC_Channels, (RC_Channels*)&plane.g2.rc_channels, read_aux_all, 10, 200, 147),
#if HAL_BUTTON_ENABLED
SCHED_TASK_CLASS(AP_Button, &plane.button, update, 5, 100, 150),
#endif
#if STATS_ENABLED == ENABLED
SCHED_TASK_CLASS(AP_Stats, &plane.g2.stats, update, 1, 100, 153),
#endif
#if GRIPPER_ENABLED == ENABLED
SCHED_TASK_CLASS(AP_Gripper, &plane.g2.gripper, update, 10, 75, 156),
#endif
#if LANDING_GEAR_ENABLED == ENABLED
SCHED_TASK(landing_gear_update, 5, 50, 159),
#endif
};
void Plane::get_scheduler_tasks(const AP_Scheduler::Task *&tasks,
uint8_t &task_count,
uint32_t &log_bit)
{
tasks = &scheduler_tasks[0];
task_count = ARRAY_SIZE(scheduler_tasks);
log_bit = MASK_LOG_PM;
}
#if HAL_QUADPLANE_ENABLED
constexpr int8_t Plane::_failsafe_priorities[7];
#else
constexpr int8_t Plane::_failsafe_priorities[6];
#endif
// 更新姿态传感器
void Plane::ahrs_update()
{
arming.update_soft_armed();
ahrs.update();
if (should_log(MASK_LOG_IMU)) {
AP::ins().Write_IMU();
}
// 根据设定的滚转角、俯仰角度,计算出按比例的滚转、俯仰限制
roll_limit_cd = aparm.roll_limit_cd;
pitch_limit_min_cd = aparm.pitch_limit_min_cd;
bool rotate_limits = true;
#if HAL_QUADPLANE_ENABLED
if (quadplane.tailsitter.active()) {
rotate_limits = false;
}
#endif
if (rotate_limits) {
roll_limit_cd *= ahrs.cos_pitch();
pitch_limit_min_cd *= fabsf(ahrs.cos_roll());
}
// 更新、汇总用于地面转向和自动起飞的陀螺仪数据。
// 通过DCM.c转换矩阵与陀螺仪矢量的点积给出了大地系的偏航率
steer_state.locked_course_err += ahrs.get_yaw_rate_earth() * G_Dt;
steer_state.locked_course_err = wrap_PI(steer_state.locked_course_err);
#if HAL_QUADPLANE_ENABLED
// 检查是否有来自EKF的重置偏航数据
quadplane.check_yaw_reset();
// 更新垂起无人机的惯性导航系统
quadplane.inertial_nav.update();
#endif
if (should_log(MASK_LOG_VIDEO_STABILISATION)) {
ahrs.write_video_stabilisation();
}
}
/*
以50Hz的频率更新速度/高度控制器
*/
void Plane::update_speed_height(void)
{
if (control_mode->does_auto_throttle()) {
// 以50Hz频率调用TECS更新
//请注意,无论油门是否被抑制,都将调用这个功能,因为需要在起50Hz飞检测中运行。
TECS_controller.update_50hz();
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode() ||
quadplane.in_assisted_flight()) {
quadplane.update_throttle_mix();
}
#endif
}
/*
读取和更新罗盘数据
*/
void Plane::update_compass(void)
{
compass.read();
}
/*
以10Hz的频率进行日志记录
*/
void Plane::update_logging10(void)
{
bool log_faster = (should_log(MASK_LOG_ATTITUDE_FULLRATE) || should_log(MASK_LOG_ATTITUDE_FAST));
if (should_log(MASK_LOG_ATTITUDE_MED) && !log_faster) {
Log_Write_Attitude();
ahrs.Write_AOA_SSA();
} else if (log_faster) {
ahrs.Write_AOA_SSA();
}
}
/*
以25Hz的频率进行日志记录
*/
void Plane::update_logging25(void)
{
// MASK LOG ATTITUDE FULLRATE以400Hz记录,MASK LOG ATTITUDE FAST以25Hz记录,MASK LOG ATTIUDE MED以10Hz记录
// 以最快速率记录
bool log_faster = should_log(MASK_LOG_ATTITUDE_FULLRATE);
if (should_log(MASK_LOG_ATTITUDE_FAST) && !log_faster) {
Log_Write_Attitude();
}
if (should_log(MASK_LOG_CTUN)) {
Log_Write_Control_Tuning();
AP::ins().write_notch_log_messages();
#if HAL_GYROFFT_ENABLED
gyro_fft.write_log_messages();
#endif
}
if (should_log(MASK_LOG_NTUN)) {
Log_Write_Nav_Tuning();
Log_Write_Guided();
}
if (should_log(MASK_LOG_RC))
Log_Write_RC();
if (should_log(MASK_LOG_IMU))
AP::ins().Write_Vibration();
}
/*
检查AFS的故障安全检测
*/
#if ADVANCED_FAILSAFE == ENABLED
void Plane::afs_fs_check(void)
{
// perform AFS failsafe checks进行AFS故障安全检查
#if AP_FENCE_ENABLED
const bool fence_breached = fence.get_breaches() != 0;
#else
const bool fence_breached = false;
#endif
afs.check(fence_breached, failsafe.AFS_last_valid_rc_ms);
}
#endif
#if HAL_WITH_IO_MCU
#include
extern AP_IOMCU iomcu;
#endif
void Plane::one_second_loop()
{
// 发射机检测逻辑 自主开发的程序 用于飞控主系统的机械开关启动
bool debug = true;
if (plane.g2.launch_detector_pin != -1) { // 启用了发射检测功能
hal.gpio->pinMode(plane.g2.launch_detector_pin, HAL_GPIO_INPUT); // 发射机检测引脚设置为GPIO输入模式
hal.gpio->write(plane.g2.launch_detector_pin, 1); // 发射检测引脚添加内部上拉
if (hal.gpio->read(plane.g2.launch_detector_pin) == plane.g2.launch_detector_polarity) { // 处于已触发状态
if (AP_HAL::millis() - plane.launch_detector_pin_last_inactive_time_ms < ((uint32_t)plane.g2.launch_detector_delay_ms)) { // 虽然已经触发,但是没有达到延时时间
debug = false;
}
} else { // 处于未触发状态
plane.launch_detector_pin_last_inactive_time_ms = AP_HAL::millis();
debug = false;
}
}
if(debug)
gcs().send_text(MAV_SEVERITY_CRITICAL, "Activate!");
else
gcs().send_text(MAV_SEVERITY_CRITICAL, "Inactivate!");
// 使之有可能在运行时改变控制频道的顺序
set_control_channels();
#if HAL_WITH_IO_MCU
iomcu.setup_mixing(&rcmap, g.override_channel.get(), g.mixing_gain, g2.manual_rc_mask);
#endif
#if HAL_ADSB_ENABLED
adsb.set_stall_speed_cm(aparm.airspeed_min * 100); // convert m/s to cm/s将m/s转化为cm/s
adsb.set_max_speed(aparm.airspeed_max);
#endif
if (g2.flight_options & FlightOptions::ENABLE_DEFAULT_AIRSPEED) {
// 使用最小和最大空速的平均值作为默认空速值以消除空速测量误差
ahrs.writeDefaultAirSpeed((float)((aparm.airspeed_min + aparm.airspeed_max)/2),
(float)((aparm.airspeed_max - aparm.airspeed_min)/2));
}
// 同步MAVLink系统ID
mavlink_system.sysid = g.sysid_this_mav;
SRV_Channels::enable_aux_servos();
// 更新通知标志
AP_Notify::flags.pre_arm_check = arming.pre_arm_checks(false);
AP_Notify::flags.pre_arm_gps_check = true;
AP_Notify::flags.armed = arming.is_armed() || arming.arming_required() == AP_Arming::Required::NO;
#if AP_TERRAIN_AVAILABLE
if (should_log(MASK_LOG_GPS)) {
terrain.log_terrain_data();
}
#endif
// 如果未解锁且GPS位置发生变化时,则更新home点位置。
// 每5秒更新一次
if (!arming.is_armed() &&
gps.last_message_time_ms() - last_home_update_ms > 5000 &&
gps.status() >= AP_GPS::GPS_OK_FIX_3D) {
last_home_update_ms = gps.last_message_time_ms();
update_home();
// 重置着陆高度的修正
landing.alt_offset = 0;
}
// 通过调用构造函数和调度器的方法,确保了启动时G_Dt的正确性。
if (!is_equal(1.0f/scheduler.get_loop_rate_hz(), scheduler.get_loop_period_s()) ||
!is_equal(G_Dt, scheduler.get_loop_period_s())) {
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
}
}
void Plane::three_hz_loop()
{
#if AP_FENCE_ENABLED
fence_check();
#endif
}
void Plane::compass_save()
{
if (AP::compass().available() &&
compass.get_learn_type() >= Compass::LEARN_INTERNAL &&
!hal.util->get_soft_armed()) {
/*
只有在上锁时才保存偏移量
*/
compass.save_offsets();
}
}
#if AP_AIRSPEED_AUTOCAL_ENABLE
/*
每秒更新一次空速校准率
*/
void Plane::airspeed_ratio_update(void)
{
if (!airspeed.enabled() ||
gps.status() < AP_GPS::GPS_OK_FIX_3D ||
gps.ground_speed() < 4) {
// 不移动时不进行校准
return;
}
if (airspeed.get_airspeed() < aparm.airspeed_min &&
gps.ground_speed() < (uint32_t)aparm.airspeed_min) {
// 当飞行速度低于最低空速时,不要进行校准。
// 我们同时检查空速和地面速度,避免空速太低的情况
return;
}
if (labs(ahrs.roll_sensor) > roll_limit_cd ||
ahrs.pitch_sensor > aparm.pitch_limit_max_cd ||
ahrs.pitch_sensor < pitch_limit_min_cd) {
// 当无人机姿态超出正常飞行允许范围时,不要校准。
return;
}
const Vector3f &vg = gps.velocity();
airspeed.update_calibration(vg, aparm.airspeed_max);
}
#endif //
/*
读取卫星定位数据并更新位置
*/
void Plane::update_GPS_50Hz(void)
{
gps.update();
update_current_loc();
}
/*
读取更新GPS位置 - 10Hz更新
*/
void Plane::update_GPS_10Hz(void)
{
static uint32_t last_gps_msg_ms;
if (gps.last_message_time_ms() != last_gps_msg_ms && gps.status() >= AP_GPS::GPS_OK_FIX_3D) {
last_gps_msg_ms = gps.last_message_time_ms();
if (ground_start_count > 1) {
ground_start_count--;
} else if (ground_start_count == 1) {
// 我们倒数N个良好的GPS固定点,确保高度数据就更准确了
// -------------------------------------
if (current_loc.lat == 0 && current_loc.lng == 0) {
ground_start_count = 5;
} else if (!hal.util->was_watchdog_reset()) {
if (!set_home_persistently(gps.location())) {
}
next_WP_loc = prev_WP_loc = home;
ground_start_count = 0;
}
}
// 更新风向评估
ahrs.estimate_wind();
} else if (gps.status() < AP_GPS::GPS_OK_FIX_3D && ground_start_count != 0) {
// 若卫星数据丢失3D定位,则重新开始
ground_start_count = 5;
}
calc_gndspeed_undershoot();
}
/*
主控模式依赖的更新代码
*/
void Plane::update_control_mode(void)
{
if (control_mode != &mode_auto) {
// 起飞和降落时锁定航向
steer_state.hold_course_cd = -1;
}
update_fly_forward();
control_mode->update();
}
void Plane::update_fly_forward(void)
{
// 确保作为纯固定翼模式飞行时是向前飞的。
// 这有助于EKF得出更好的状态评估,因为它可以做出更强的假设
#if HAL_QUADPLANE_ENABLED
if (quadplane.available() &&
quadplane.tailsitter.is_in_fw_flight()) {
ahrs.set_fly_forward(true);
return;
}
if (quadplane.in_vtol_mode() ||
quadplane.in_assisted_flight()) {
ahrs.set_fly_forward(false);
return;
}
#endif
if (flight_stage == AP_Vehicle::FixedWing::FLIGHT_LAND) {
ahrs.set_fly_forward(landing.is_flying_forward());
return;
}
ahrs.set_fly_forward(true);
}
/*
设置飞行阶段
*/
void Plane::set_flight_stage(AP_Vehicle::FixedWing::FlightStage fs)
{
if (fs == flight_stage) {
return;
}
landing.handle_flight_stage_change(fs == AP_Vehicle::FixedWing::FLIGHT_LAND);
if (fs == AP_Vehicle::FixedWing::FLIGHT_ABORT_LAND) {
gcs().send_text(MAV_SEVERITY_NOTICE, "Landing aborted, climbing to %dm",
int(auto_state.takeoff_altitude_rel_cm/100));
}
flight_stage = fs;
Log_Write_Status();
}
void Plane::update_alt()
{
barometer.update();
#if HAL_QUADPLANE_ENABLED
if (quadplane.available()) {
quadplane.motors->set_air_density_ratio(barometer.get_air_density_ratio());
}
#endif
// 计算下沉率。
float sink_rate;
Vector3f vel;
if (ahrs.get_velocity_NED(vel)) {
sink_rate = vel.z;
} else if (gps.status() >= AP_GPS::GPS_OK_FIX_3D && gps.have_vertical_velocity()) {
sink_rate = gps.velocity().z;
} else {
sink_rate = -barometer.get_climb_rate();
}
// 通过低通滤波器消除下沉率中的噪音
auto_state.sink_rate = 0.8f * auto_state.sink_rate + 0.2f*sink_rate;
#if PARACHUTE == ENABLED
parachute.set_sink_rate(auto_state.sink_rate);
#endif
update_flight_stage();
if (control_mode->does_auto_throttle() && !throttle_suppressed) {
float distance_beyond_land_wp = 0;
if (flight_stage == AP_Vehicle::FixedWing::FLIGHT_LAND && current_loc.past_interval_finish_line(prev_WP_loc, next_WP_loc)) {
distance_beyond_land_wp = current_loc.get_distance(next_WP_loc);
}
tecs_target_alt_cm = relative_target_altitude_cm();
if (control_mode == &mode_rtl && !rtl.done_climb && (g2.rtl_climb_min > 0 || (plane.g2.flight_options & FlightOptions::CLIMB_BEFORE_TURN))) {
// 确保我们在RTL中进行初始爬升。我们在要求的高度上额外增加10米,以推动TECS快速爬升。
tecs_target_alt_cm = MAX(tecs_target_alt_cm, prev_WP_loc.alt - home.alt) + (g2.rtl_climb_min+10)*100;
}
TECS_controller.update_pitch_throttle(tecs_target_alt_cm,
target_airspeed_cm,
flight_stage,
distance_beyond_land_wp,
get_takeoff_pitch_min_cd(),
throttle_nudge,
tecs_hgt_afe(),
aerodynamic_load_factor);
}
}
/*
重新计算飞行阶段
*/
void Plane::update_flight_stage(void)
{
// 更新速度和高度控制器的状态
if (control_mode->does_auto_throttle() && !throttle_suppressed) {
if (control_mode == &mode_auto) {
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_auto()) {
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_VTOL);
return;
}
#endif
if (auto_state.takeoff_complete == false) {
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_TAKEOFF);
return;
} else if (mission.get_current_nav_cmd().id == MAV_CMD_NAV_LAND) {
if (landing.is_commanded_go_around() || flight_stage == AP_Vehicle::FixedWing::FLIGHT_ABORT_LAND) {
// 终止模式是棘手的,它必须在执行NAV_LAND时完成时才被允许。
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_ABORT_LAND);
} else if (landing.get_abort_throttle_enable() && get_throttle_input() >= 90 &&
landing.request_go_around()) {
gcs().send_text(MAV_SEVERITY_INFO,"Landing aborted via throttle");
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_ABORT_LAND);
} else {
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_LAND);
}
return;
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_assisted_flight()) {
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_VTOL);
return;
}
#endif
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_NORMAL);
} else if (control_mode != &mode_takeoff) {
// 如果不是在自动模式下,则假定在正常操作,以实现TECS的正常运行。
// 这可以防止TECS在着陆、中止着陆或起飞过程中,从自动模式切换到例如FBWB时,被卡在错误的阶段。
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_NORMAL);
}
return;
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode() ||
quadplane.in_assisted_flight()) {
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_VTOL);
return;
}
#endif
set_flight_stage(AP_Vehicle::FixedWing::FLIGHT_NORMAL);
}
/*
如果着陆解除延迟被启用(非零),检查是否有着陆,然后在时间结束后自动解锁。
当着陆库准备解锁时,只从AP_Landing调用。
*/
void Plane::disarm_if_autoland_complete()
{
if (landing.get_disarm_delay() > 0 &&
!is_flying() &&
arming.arming_required() != AP_Arming::Required::NO &&
arming.is_armed()) {
/* 已经启用了自动解锁。看看是否已经过了足够的时间 */
if (millis() - auto_state.last_flying_ms >= landing.get_disarm_delay()*1000UL) {
if (arming.disarm(AP_Arming::Method::AUTOLANDED)) {
gcs().send_text(MAV_SEVERITY_INFO,"Auto disarmed");
}
}
}
}
/*
传递给TECS的现场海拔高度
*/
float Plane::tecs_hgt_afe(void)
{
/*
将场内海拔以上的高度传递为着陆时距离地面的高度。
这意味着TECS得到了测距仪的信息,从而可以知道突变在何时发生。
*/
float hgt_afe;
if (flight_stage == AP_Vehicle::FixedWing::FLIGHT_LAND) {
hgt_afe = height_above_target();
hgt_afe -= rangefinder_correction();
} else {
// 在正常飞行时,我们将hgt_afe作为相对高度传递给家位置。
hgt_afe = relative_altitude;
}
return hgt_afe;
}
// 飞行器特定的航点信息帮助工具
bool Plane::get_wp_distance_m(float &distance) const
{
// 见 GCS_MAVLINK_Plane::send_nav_controller_output()
if (control_mode == &mode_manual) {
return false;
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode()) {
distance = quadplane.using_wp_nav() ? quadplane.wp_nav->get_wp_distance_to_destination() * 0.01 : 0;
return true;
}
#endif
distance = auto_state.wp_distance;
return true;
}
bool Plane::get_wp_bearing_deg(float &bearing) const
{
// 见 GCS_MAVLINK_Plane::send_nav_controller_output()
if (control_mode == &mode_manual) {
return false;
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode()) {
bearing = quadplane.using_wp_nav() ? quadplane.wp_nav->get_wp_bearing_to_destination() : 0;
return true;
}
#endif
bearing = nav_controller->target_bearing_cd() * 0.01;
return true;
}
bool Plane::get_wp_crosstrack_error_m(float &xtrack_error) const
{
// 见 GCS_MAVLINK_Plane::send_nav_controller_output()
if (control_mode == &mode_manual) {
return false;
}
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode()) {
xtrack_error = quadplane.using_wp_nav() ? quadplane.wp_nav->crosstrack_error() : 0;
return true;
}
#endif
xtrack_error = nav_controller->crosstrack_error();
return true;
}
#if AP_SCRIPTING_ENABLED
// 设置目标位置(供脚本使用)
bool Plane::set_target_location(const Location &target_loc)
{
Location loc{target_loc};
if (plane.control_mode != &plane.mode_guided) {
// 只在引导模式下接受位置更新
return false;
}
// 如有需要,可添加首页的备选方案
if (loc.relative_alt) {
loc.alt += plane.home.alt;
loc.relative_alt = 0;
}
plane.set_guided_WP(loc);
return true;
}
// 设置目标位置(供脚本使用)
bool Plane::get_target_location(Location& target_loc)
{
switch (control_mode->mode_number()) {
case Mode::Number::RTL:
case Mode::Number::AVOID_ADSB:
case Mode::Number::GUIDED:
case Mode::Number::AUTO:
case Mode::Number::LOITER:
case Mode::Number::TAKEOFF:
#if HAL_QUADPLANE_ENABLED
case Mode::Number::QLOITER:
case Mode::Number::QLAND:
case Mode::Number::QRTL:
#endif
target_loc = next_WP_loc;
return true;
break;
default:
break;
}
return false;
}
/*
更新目标位置()在所有自动导航模式下都能工作
*/
bool Plane::update_target_location(const Location &old_loc, const Location &new_loc)
{
if (!old_loc.same_latlon_as(next_WP_loc)) {
return false;
}
ftype alt_diff;
if (!old_loc.get_alt_distance(next_WP_loc, alt_diff) ||
!is_zero(alt_diff)) {
return false;
}
next_WP_loc = new_loc;
next_WP_loc.change_alt_frame(old_loc.get_alt_frame());
return true;
}
// 允许在VTOL中进行速度匹配
bool Plane::set_velocity_match(const Vector2f &velocity)
{
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_mode() || quadplane.in_vtol_land_sequence()) {
quadplane.poscontrol.velocity_match = velocity;
quadplane.poscontrol.last_velocity_match_ms = AP_HAL::millis();
return true;
}
#endif
return false;
}
#endif // AP_SCRIPTING_ENABLED
// 在非VTOL模式下为TRIM_PITCH_CD纠正AHRS俯仰,并在VTOL模式下返回VTOL视图
void Plane::get_osd_roll_pitch_rad(float &roll, float &pitch) const
{
#if HAL_QUADPLANE_ENABLED
if (quadplane.show_vtol_view()) {
pitch = quadplane.ahrs_view->pitch;
roll = quadplane.ahrs_view->roll;
return;
}
#endif
pitch = ahrs.pitch;
roll = ahrs.roll;
if (!(g2.flight_options & FlightOptions::OSD_REMOVE_TRIM_PITCH_CD)) { // correct for TRIM_PITCH_CD 更正TRIM_PITCH_CD
pitch -= g.pitch_trim_cd * 0.01 * DEG_TO_RAD;
}
}
/*
更新当前位置
*/
void Plane::update_current_loc(void)
{
have_position = plane.ahrs.get_location(plane.current_loc);
// 重新计算相对海拔
ahrs.get_relative_position_D_home(plane.relative_altitude);
relative_altitude *= -1.0f;
}
AP_HAL_MAIN_CALLBACKS(&plane);