如何根据GPS定位信息进行位置控制?
经纬度海拔高度如何转成导航坐标系?
飞控中的航迹点waypoint是基于那个坐标系的点?导航坐标系?
Home点?导航坐标系的原点?电机解锁时的点?xyz?
上电的时刻先建立一个NED全局坐标?
设置Home点的线程:
// update home from EKF if necessary
FAST_TASK(update_home_from_EKF),
根据以下代码可知,电机解锁时设置当前位置为Home点;
// checks if we should update ahrs/RTL home position from the EKF
void Copter::update_home_from_EKF()
{
// exit immediately if home already set
if (ahrs.home_is_set()) {
return;
}
// special logic if home is set in-flight
if (motors->armed()) {
set_home_to_current_location_inflight();
} else {
// move home to current ekf location (this will set home_state to HOME_SET)
if (!set_home_to_current_location(false)) {
// ignore failure
}
}
}
调用的地方:
// update angle targets that will be passed to stabilize controller
accel_to_lean_angles(_accel_target.x, _accel_target.y, _roll_target, _pitch_target);
calculate_yaw_and_rate_yaw();
定义的地方:
// get_lean_angles_to_accel - convert roll, pitch lean angles to NE frame accelerations in cm/s/s
void AC_PosControl::accel_to_lean_angles(float accel_x_cmss, float accel_y_cmss, float& roll_target, float& pitch_target) const
没错了,引用类型的量是被赋值的量,按这个原则去分析准没错;
void AC_PosControl::accel_to_lean_angles(float accel_x_cmss, float accel_y_cmss, float& roll_target, float& pitch_target) const
{
// rotate accelerations into body forward-right frame
const float accel_forward = accel_x_cmss * _ahrs.cos_yaw() + accel_y_cmss * _ahrs.sin_yaw();
const float accel_right = -accel_x_cmss * _ahrs.sin_yaw() + accel_y_cmss * _ahrs.cos_yaw();
// update angle targets that will be passed to stabilize controller
pitch_target = accel_to_angle(-accel_forward * 0.01) * 100;
float cos_pitch_target = cosf(pitch_target * M_PI / 18000.0f);
roll_target = accel_to_angle((accel_right * cos_pitch_target)*0.01) * 100;
}
那 NEU 系下的目标加速度怎么来的?
即谁更新了_accel_target.x, _accel_target.y 的值??或谁负责更新的_accel_target??
向上追溯、查找发现:
要不先看定义吧:
case SubMode::CIRCLE_MOVE_TO_EDGE:
wp_run();
break;
/// advance_wp_target_along_track - move target location along track from origin to destination
bool AC_WPNav::advance_wp_target_along_track(float dt)
当前时刻的期望位置如何获取这里不在赘叙…
AC_P_2D _p_pos_xy; // XY axis position controller to convert distance error to desired velocity
AC_PID_2D _pid_vel_xy; // XY axis velocity controller to convert velocity error to desired acceleration
位置控制器的结构是:p位置 ~> pid 速度 ~> 加速度 ~>飞机倾角 的这样一种串联结构,控制器实例调用本身的 update_all 就可以计算出控制量:
显而易见,p位置控制器的输出是期望速度值:
// Position Controller
const Vector3f &curr_pos = _inav.get_position_neu_cm();
Vector2f vel_target = _p_pos_xy.update_all(_pos_target.x, _pos_target.y, curr_pos);
pid速度控制器的输出是期望加速度值:
// Velocity Controller
const Vector2f &curr_vel = _inav.get_velocity_xy_cms();
Vector2f accel_target = _pid_vel_xy.update_all(_vel_target.xy(), curr_vel, _dt, _limit_vector.xy());
加速度控制器的输出是姿态内环的期望姿态角(倾角),此处的加速度控制器其实是一种加速度到倾角的映射,代码中用函数accel_to_lean_angles实现,如下代码所示:
// Acceleration Controller
// limit acceleration using maximum lean angles
float angle_max = MIN(_attitude_control.get_althold_lean_angle_max_cd(), get_lean_angle_max_cd());
float accel_max = angle_to_accel(angle_max * 0.01) * 100;
// Define the limit vector before we constrain _accel_target
_limit_vector.xy() = _accel_target.xy();
if (!limit_accel_xy(_vel_desired.xy(), _accel_target.xy(), accel_max)) {
// _accel_target was not limited so we can zero the xy limit vector
_limit_vector.xy().zero();
}
// update angle targets that will be passed to stabilize controller
accel_to_lean_angles(_accel_target.x, _accel_target.y, _roll_target, _pitch_target);
// update_all - set target and measured inputs to PID controller and calculate outputs
// target and error are filtered
// the derivative is then calculated and filtered
// the integral is then updated based on the setting of the limit flag
float AC_PID::update_all(float target, float measurement, float dt, bool limit, float boost)
{
// don't process inf or NaN
if (!isfinite(target) || !isfinite(measurement)) {
return 0.0f;
}
// reset input filter to value received
if (_flags._reset_filter) {
_flags._reset_filter = false;
_target = target;
_error = _target - measurement;
_derivative = 0.0f;
} else {
float error_last = _error;
_target += get_filt_T_alpha(dt) * (target - _target);
_error += get_filt_E_alpha(dt) * ((_target - measurement) - _error);
// calculate and filter derivative
if (is_positive(dt)) {
float derivative = (_error - error_last) / dt;
_derivative += get_filt_D_alpha(dt) * (derivative - _derivative);
}
}
// update I term
update_i(dt, limit);
float P_out = (_error * _kp);
float D_out = (_derivative * _kd);
// calculate slew limit modifier for P+D
_pid_info.Dmod = _slew_limiter.modifier((_pid_info.P + _pid_info.D) * _slew_limit_scale, dt);
_pid_info.slew_rate = _slew_limiter.get_slew_rate();
P_out *= _pid_info.Dmod;
D_out *= _pid_info.Dmod;
// boost output if required
P_out *= boost;
D_out *= boost;
_pid_info.target = _target;
_pid_info.actual = measurement;
_pid_info.error = _error;
_pid_info.P = P_out;
_pid_info.D = D_out;
return P_out + _integrator + D_out;
}
curr_pos = _inav.get_position_neu_cm()
// references to inertial nav and ahrs libraries
const AP_InertialNav& _inav;
_relpos_cm :position relative
// get the NE position relative to the local earth frame origin
Vector2f posNE;
if (_ahrs_ekf.get_relative_position_NE_origin(posNE)) {
_relpos_cm.x = posNE.x * 100; // convert from m to cm
_relpos_cm.y = posNE.y * 100; // convert from m to cm
}
// get the D position relative to the local earth frame origin
float posD;
if (_ahrs_ekf.get_relative_position_D_origin(posD)) {
_relpos_cm.z = - posD * 100; // convert from m in NED to cm in NEU
}
AP_AHRS &_ahrs_ekf;
AHRS:状态估计器,包括姿态速度,位置信息,
AHRS调用了EKF和的信息:
#include
#include
#include
bool position_is_valid = EKF3.getPosNE(posNE);
// This is the normal mode of operation where we can use the EKF position states
// correct for the IMU offset (EKF calculations are at the IMU)
posNE.x = outputDataNew.position.x + posOffsetNED.x;
posNE.y = outputDataNew.position.y + posOffsetNED.y;
机体系原点相对于参考点(全局坐标系NED)的位置估计??
outputDataNew.position是IMU速度积分得到的位置信息:
// apply a trapezoidal integration to velocities to calculate position
outputDataNew.position += (outputDataNew.velocity + lastVelocity) * (imuDataNew.delVelDT*0.5f);
posOffsetNED是为了防止积分误差而引入的偏置,来源于GPS?
Vector3F accelPosOffset; ://IMU加速计单元在车身框架中的位置(m)
// calculate the earth frame position of the body frame origin relative to the IMU
posOffsetNED = Tbn_temp * (- accelPosOffset);
Tbn_temp :机体系到地面系的旋转矩阵;