位置:X:\ardupilot\ArduCopter\navigation.cpp
// run_nav_updates - top level call for the autopilot
// ensures calculations such as "distance to waypoint" are calculated before autopilot makes decisions
// To-Do - rename and move this function to make it's purpose more clear
void Copter::run_nav_updates(void)
{
update_super_simple_bearing(false);
flightmode->update_navigation();
}
位置:X:\ardupilot\ArduCopter\ArduCopter.cpp
// update_super_simple_bearing - adjusts simple bearing based on location
// should be called after home_bearing has been updated
void Copter::update_super_simple_bearing(bool force_update)//false
{
if (!force_update) {
if (ap.simple_mode != 2) {
return;
}
if (home_distance() < SUPER_SIMPLE_RADIUS) {//1000
return;
}
}
const int32_t bearing = home_bearing();
// check the bearing to home has changed by at least 5 degrees
if (labs(super_simple_last_bearing - bearing) < 500) {
return;//角度小于5度,不执行后面的代码;超过5度时,执行
}
super_simple_last_bearing = bearing;//记录当前的角度
const float angle_rad = radians((super_simple_last_bearing+18000)/100);
super_simple_cos_yaw = cosf(angle_rad);
super_simple_sin_yaw = sinf(angle_rad);//计算SUPER_SIMPLE模式下的偏航角的正余弦
}
// distance between vehicle and home in cm
uint32_t Copter::home_distance()
{
if (position_ok()) {//如果位置估计有效的话,计算距离
const Vector3f home = pv_location_to_vector(ahrs.get_home());
const Vector3f curr = inertial_nav.get_position();
_home_distance = get_horizontal_distance_cm(curr, home);//计算距离家的水平距离
}
return _home_distance;
}
位置:X:\ardupilot\ArduCopter\system.cpp
// position_ok - returns true if the horizontal absolute position is ok and home position is set
bool Copter::position_ok()
{
// return false if ekf failsafe has triggered
if (failsafe.ekf) {
return false;
}
// check ekf position estimate
return (ekf_position_ok() || optflow_position_ok());
}
// ekf_position_ok - returns true if the ekf claims it's horizontal absolute position estimate is ok and home position is set
bool Copter::ekf_position_ok()
{
if (!ahrs.have_inertial_nav()) {
// do not allow navigation with dcm position(不允许使用dcm位置导航)
return false;
}
// with EKF use filter status and ekf check(使用EKF使用过滤器状态和EKF检查)
nav_filter_status filt_status = inertial_nav.get_filter_status();
// if disarmed we accept a predicted horizontal position
if (!motors->armed()) {
return ((filt_status.flags.horiz_pos_abs || filt_status.flags.pred_horiz_pos_abs));
} else {
// once armed we require a good absolute position and EKF must not be in const_pos_mode
//一旦解锁,我们就需要一个好的绝对位置而EKF不能在const_pos_mode
return (filt_status.flags.horiz_pos_abs && !filt_status.flags.const_pos_mode);
}
}
// optflow_position_ok - returns true if optical flow based position estimate is ok
bool Copter::optflow_position_ok()
{
#if OPTFLOW != ENABLED && VISUAL_ODOMETRY_ENABLED != ENABLED
return false;//光流和视觉里程计未开启的话,直接退出,返回FALSE
#else
// return immediately if EKF not used(如果EKF不使用,立即返回)
if (!ahrs.have_inertial_nav()) {
return false;
}
// return immediately if neither optflow nor visual odometry is enabled(如果不启用optflow或visual odom测量,则立即返回)
bool enabled = false;
#if OPTFLOW == ENABLED
if (optflow.enabled()) {//判断光流是否可用
enabled = true;
}
#endif
#if VISUAL_ODOMETRY_ENABLED == ENABLED
if (g2.visual_odom.enabled()) {//判断视觉是否可用
enabled = true;
}
#endif
if (!enabled) {//如果不可用的话,退出
return false;
}
// get filter status from EKF(从EKF获得过滤状态)
nav_filter_status filt_status = inertial_nav.get_filter_status();
// if disarmed we accept a predicted horizontal relative position(如果没有解锁,我们接受一个预测的相对水平位置)
if (!motors->armed()) {
return (filt_status.flags.pred_horiz_pos_rel);
} else {
return (filt_status.flags.horiz_pos_rel && !filt_status.flags.const_pos_mode);
}
#endif
}
位置:X:\ardupilot\ArduCopter\position_vector.cpp
// pv_location_to_vector - convert lat/lon coordinates to a position vector(将纬度/经度坐标转换为位置矢量)
Vector3f Copter::pv_location_to_vector(const Location& loc)//ahrs.get_home()
{
const struct Location &origin = inertial_nav.get_origin();//获取惯性导航的原点
float alt_above_origin = pv_alt_above_origin(loc.alt); // convert alt-relative-to-home to alt-relative-to-origin
return Vector3f((loc.lat-origin.lat) * LATLON_TO_CM, (loc.lng-origin.lng) * LATLON_TO_CM * scaleLongDown, alt_above_origin);
}
// pv_alt_above_origin - convert altitude above home to altitude above EKF origin
float Copter::pv_alt_above_origin(float alt_above_home_cm)//相对于HOME点的高度
{
const struct Location &origin = inertial_nav.get_origin();//惯性导航原点的坐标
return alt_above_home_cm + (ahrs.get_home().alt - origin.alt);//alt_above_home_cm = ahrs.get_home().alt
}
位置:X:\ardupilot\ArduCopter\navigation.cpp
// The location of home in relation to the vehicle in centi-degrees
int32_t Copter::home_bearing()
{
if (position_ok()) {
const Vector3f home = pv_location_to_vector(ahrs.get_home());
const Vector3f curr = inertial_nav.get_position();
_home_bearing = get_bearing_cd(curr,home);
}
return _home_bearing;
}
位置:X:\ardupilot\libraries\AP_Math\location.cpp
// return bearing in centi-degrees between two locations
int32_t get_bearing_cd(const struct Location &loc1, const struct Location &loc2)
{
int32_t off_x = loc2.lng - loc1.lng;
int32_t off_y = (loc2.lat - loc1.lat) / longitude_scale(loc2);
int32_t bearing = 9000 + atan2f(-off_y, off_x) * DEGX100;
if (bearing < 0) bearing += 36000;
return bearing;
}
位置:X:\ardupilot\libraries\AP_Math\location.cpp
float longitude_scale(const struct Location &loc)
{
float scale = cosf(loc.lat * 1.0e-7f * DEG_TO_RAD);
return constrain_float(scale, 0.01f, 1.0f);
}
位置:X:\ardupilot\ArduCopter\mode.cpp
void Copter::Mode::update_navigation()
{
// run autopilot to make high level decisions about control modes(运行自动驾驶仪,对控制模式做出高水平的决策)
run_autopilot();
}
对run_autopilot进行全局搜索之后,只有在mode_auto.cpp中,对这个虚函数做了实现。
位置:X:\ardupilot\ArduCopter\mode_auto.cpp
// update mission
void Copter::ModeAuto::run_autopilot()//
{
copter.mission.update();
}
位置:X:\ardupilot\libraries\AP_Mission\AP_Mission.cpp
/// update - ensures the command queues are loaded with the next command and calls main programs command_init and command_verify functions to progress the mission
/// should be called at 10hz or higher
void AP_Mission::update()//
{
// exit immediately if not running or no mission commands(如果不运行或没有任务命令,立即退出)
if (_flags.state != MISSION_RUNNING || _cmd_total == 0) {
return;
}
// check if we have an active nav command(检查我们是否有一个活动的nav命令)
if (!_flags.nav_cmd_loaded || _nav_cmd.index == AP_MISSION_CMD_INDEX_NONE) {
// advance in mission if no active nav command(如果没有主动导航命令,在任务中前进)
if (!advance_current_nav_cmd()) {
// failure to advance nav command means mission has completed(未能推进导航命令意味着任务已经完成)
complete();
return;
}
}else{
// run the active nav command
if (_cmd_verify_fn(_nav_cmd)) {
// market _nav_cmd as complete (it will be started on the next iteration)
_flags.nav_cmd_loaded = false;
// immediately advance to the next mission command
if (!advance_current_nav_cmd()) {
// failure to advance nav command means mission has completed
complete();
return;
}
}
}
// check if we have an active do command
if (!_flags.do_cmd_loaded) {
advance_current_do_cmd();
}else{
// run the active do command
if (_cmd_verify_fn(_do_cmd)) {
// market _nav_cmd as complete (it will be started on the next iteration)
_flags.do_cmd_loaded = false;
}
}
}
位置:X:\ardupilot\libraries\AP_Mission\AP_Mission.cpp
/// advance_current_nav_cmd - moves current nav command forward
/// do command will also be loaded
/// accounts for do-jump commands
// returns true if command is advanced, false if failed (i.e. mission completed)
bool AP_Mission::advance_current_nav_cmd()
{
Mission_Command cmd;
uint16_t cmd_index;
// exit immediately if we're not running
if (_flags.state != MISSION_RUNNING) {
return false;
}
// exit immediately if current nav command has not completed
if (_flags.nav_cmd_loaded) {
return false;
}
// stop the current running do command
_do_cmd.index = AP_MISSION_CMD_INDEX_NONE;//65535
_flags.do_cmd_loaded = false;
_flags.do_cmd_all_done = false;
// get starting point for search
cmd_index = _nav_cmd.index;
if (cmd_index == AP_MISSION_CMD_INDEX_NONE) {//65535
// start from beginning of the mission command list
cmd_index = AP_MISSION_FIRST_REAL_COMMAND;//1
}else{
// start from one position past the current nav command
cmd_index++;
}
// avoid endless loops
uint8_t max_loops = 255;
// search until we find next nav command or reach end of command list
while (!_flags.nav_cmd_loaded) {//检测到导航命令之后退出
// get next command
if (!get_next_cmd(cmd_index, cmd, true)) {
return false;
}
// check if navigation or "do" command
if (is_nav_cmd(cmd)) {
// save previous nav command index
_prev_nav_cmd_id = _nav_cmd.id;
_prev_nav_cmd_index = _nav_cmd.index;
// save separate previous nav command index if it contains lat,long,alt
if (!(cmd.content.location.lat == 0 && cmd.content.location.lng == 0)) {
_prev_nav_cmd_wp_index = _nav_cmd.index;//存储导航命令之前的索引
}
// set current navigation command and start it
_nav_cmd = cmd;//将获取的导航命令赋给,要执行的导航命令的位置
_flags.nav_cmd_loaded = true;//检测到导航命令,执行
_cmd_start_fn(_nav_cmd);
}else{
// set current do command and start it (if not already set)
if (!_flags.do_cmd_loaded) {
_do_cmd = cmd;
_flags.do_cmd_loaded = true;
_cmd_start_fn(_do_cmd);
} else {
// protect against endless loops of do-commands
if (max_loops-- == 0) {
return false;
}
}
}
// move onto next command
cmd_index = cmd.index+1;
}
// if we have not found a do command then set flag to show there are no do-commands to be run before nav command completes
if (!_flags.do_cmd_loaded) {
_flags.do_cmd_all_done = true;//在导航命令完成之前,不会执行do-命令。
}
// if we got this far we must have successfully advanced the nav command
return true;
}
/// complete - mission is marked complete and clean-up performed including calling the mission_complete_fn
void AP_Mission::complete()
{
// flag mission as complete
_flags.state = MISSION_COMPLETE;
// callback to main program's mission complete function
_mission_complete_fn();//这里还需要继续跟踪
}
// constructor
AP_Mission(AP_AHRS &ahrs, mission_cmd_fn_t cmd_start_fn, mission_cmd_fn_t cmd_verify_fn, mission_complete_fn_t mission_complete_fn) :
_ahrs(ahrs),
_cmd_start_fn(cmd_start_fn),
_cmd_verify_fn(cmd_verify_fn),
_mission_complete_fn(mission_complete_fn),//初始化,第四个参数
_prev_nav_cmd_id(AP_MISSION_CMD_ID_NONE),
_prev_nav_cmd_index(AP_MISSION_CMD_INDEX_NONE),
_prev_nav_cmd_wp_index(AP_MISSION_CMD_INDEX_NONE),
_last_change_time_ms(0)
{
// load parameter defaults
AP_Param::setup_object_defaults(this, var_info);
// clear commands
_nav_cmd.index = AP_MISSION_CMD_INDEX_NONE;
_do_cmd.index = AP_MISSION_CMD_INDEX_NONE;
// initialise other internal variables
_flags.state = MISSION_STOPPED;
_flags.nav_cmd_loaded = false;
_flags.do_cmd_loaded = false;
}
位置:X:\ardupilot\ArduCopter\Copter.h
// Mission library
AP_Mission mission{ahrs,
FUNCTOR_BIND_MEMBER(&Copter::start_command, bool, const AP_Mission::Mission_Command &),
FUNCTOR_BIND_MEMBER(&Copter::verify_command_callback, bool, const AP_Mission::Mission_Command &),
FUNCTOR_BIND_MEMBER(&Copter::exit_mission, void)};
void exit_mission() {
mode_auto.exit_mission();
}
位置:X:\ardupilot\ArduCopter\commands_logic.cpp
// exit_mission - function that is called once the mission completes(任务完成后调用的函数)
void Copter::ModeAuto::exit_mission()
{
// play a tone
AP_Notify::events.mission_complete = 1;
// if we are not on the ground switch to loiter or land(如果我们不在地面上切换到loiter或陆地)
if(!ap.land_complete) {
// try to enter loiter but if that fails land(试着进入loiter但如果这失败了)
if(!loiter_start()) {
set_mode(LAND, MODE_REASON_MISSION_END);
}
}else{
// if we've landed it's safe to disarm(如果我们着陆了,可以安全的上锁)
copter.init_disarm_motors();
}
}
位置:X:\ardupilot\ArduCopter\mode_auto.cpp
// auto_loiter_start - initialises loitering in auto mode
// returns success/failure because this can be called by exit_mission
bool Copter::ModeAuto::loiter_start()
{
// return failure if GPS is bad(如果GPS不好,返回失败)
if (!copter.position_ok()) {
return false;
}
_mode = Auto_Loiter;
// calculate stopping point(计算停止点)
Vector3f stopping_point;
wp_nav->get_wp_stopping_point(stopping_point);
// initialise waypoint controller target to stopping point(将waypoint控制器目标初始化到停止点)
wp_nav->set_wp_destination(stopping_point);
// hold yaw at current heading(在当前航向保持偏航)
set_auto_yaw_mode(AUTO_YAW_HOLD);
return true;
}
/// get_wp_stopping_point - returns vector to stopping point based on 3D position and velocity
void AC_WPNav::get_wp_stopping_point(Vector3f& stopping_point) const
{
_pos_control.get_stopping_point_xy(stopping_point);
_pos_control.get_stopping_point_z(stopping_point);
}
/// get_stopping_point_xy - calculates stopping point based on current position, velocity, vehicle acceleration
/// distance_max allows limiting distance to stopping point
/// results placed in stopping_position vector
/// set_accel_xy() should be called before this method to set vehicle acceleration
/// set_leash_length() should have been called before this method
void AC_PosControl::get_stopping_point_xy(Vector3f &stopping_point) const
{
const Vector3f curr_pos = _inav.get_position();
Vector3f curr_vel = _inav.get_velocity();
float linear_distance; // the distance at which we swap from a linear to sqrt response
float linear_velocity; // the velocity above which we swap from a linear to sqrt response
float stopping_dist; // the distance within the vehicle can stop
float kP = _p_pos_xy.kP();
// add velocity error to current velocity
if (is_active_xy()) {
curr_vel.x += _vel_error.x;
curr_vel.y += _vel_error.y;
}
// calculate current velocity
float vel_total = norm(curr_vel.x, curr_vel.y);
// avoid divide by zero by using current position if the velocity is below 10cm/s, kP is very low or acceleration is zero
if (kP <= 0.0f || _accel_cms <= 0.0f || is_zero(vel_total)) {
stopping_point.x = curr_pos.x;
stopping_point.y = curr_pos.y;
return;
}
// calculate point at which velocity switches from linear to sqrt
linear_velocity = _accel_cms/kP;
// calculate distance within which we can stop
if (vel_total < linear_velocity) {
stopping_dist = vel_total/kP;
} else {
linear_distance = _accel_cms/(2.0f*kP*kP);
stopping_dist = linear_distance + (vel_total*vel_total)/(2.0f*_accel_cms);
}
// constrain stopping distance
stopping_dist = constrain_float(stopping_dist, 0, _leash);
// convert the stopping distance into a stopping point using velocity vector
stopping_point.x = curr_pos.x + (stopping_dist * curr_vel.x / vel_total);
stopping_point.y = curr_pos.y + (stopping_dist * curr_vel.y / vel_total);
}
/// get_stopping_point_z - calculates stopping point based on current position, velocity, vehicle acceleration
void AC_PosControl::get_stopping_point_z(Vector3f& stopping_point) const
{
const float curr_pos_z = _inav.get_altitude();
float curr_vel_z = _inav.get_velocity_z();
float linear_distance; // half the distance we swap between linear and sqrt and the distance we offset sqrt
float linear_velocity; // the velocity we swap between linear and sqrt
// if position controller is active add current velocity error to avoid sudden jump in acceleration
if (is_active_z()) {
curr_vel_z += _vel_error.z;
if (_flags.use_desvel_ff_z) {
curr_vel_z -= _vel_desired.z;
}
}
// avoid divide by zero by using current position if kP is very low or acceleration is zero
if (_p_pos_z.kP() <= 0.0f || _accel_z_cms <= 0.0f) {
stopping_point.z = curr_pos_z;
return;
}
// calculate the velocity at which we switch from calculating the stopping point using a linear function to a sqrt function
linear_velocity = _accel_z_cms/_p_pos_z.kP();
if (fabsf(curr_vel_z) < linear_velocity) {
// if our current velocity is below the cross-over point we use a linear function
stopping_point.z = curr_pos_z + curr_vel_z/_p_pos_z.kP();
} else {
linear_distance = _accel_z_cms/(2.0f*_p_pos_z.kP()*_p_pos_z.kP());
if (curr_vel_z > 0){
stopping_point.z = curr_pos_z + (linear_distance + curr_vel_z*curr_vel_z/(2.0f*_accel_z_cms));
} else {
stopping_point.z = curr_pos_z - (linear_distance + curr_vel_z*curr_vel_z/(2.0f*_accel_z_cms));
}
}
stopping_point.z = constrain_float(stopping_point.z, curr_pos_z - POSCONTROL_STOPPING_DIST_DOWN_MAX, curr_pos_z + POSCONTROL_STOPPING_DIST_UP_MAX);
}
位置:X:\ardupilot\libraries\AC_WPNav\AC_WPNav.cpp
/// set_wp_destination waypoint using location class
/// returns false if conversion from location to vector from ekf origin cannot be calculated
bool AC_WPNav::set_wp_destination(const Location_Class& destination)
{
bool terr_alt;
Vector3f dest_neu;
// convert destination location to vector(将目标位置转换为矢量)
if (!get_vector_NEU(destination, dest_neu, terr_alt)) {
return false;
}
// set target as vector from EKF origin(将目标设定为来自EKF原点的矢量)
return set_wp_destination(dest_neu, terr_alt);
}
/// set_wp_destination waypoint using position vector (distance from home in cm)
/// terrain_alt should be true if destination.z is a desired altitude above terrain
bool AC_WPNav::set_wp_destination(const Vector3f& destination, bool terrain_alt)
{
Vector3f origin;
// if waypoint controller is active use the existing position target as the origin
if ((AP_HAL::millis() - _wp_last_update) < 1000) {
origin = _pos_control.get_pos_target();//最近1秒内使用过waypoint
} else {
// if waypoint controller is not active, set origin to reasonable stopping point (using curr pos and velocity)
_pos_control.get_stopping_point_xy(origin);
_pos_control.get_stopping_point_z(origin);
}
// convert origin to alt-above-terrain(转换为地形高度)
if (terrain_alt) {
float origin_terr_offset;
if (!get_terrain_offset(origin_terr_offset)) {
return false;
}
origin.z -= origin_terr_offset;//修正高度
}
// set origin and destination(设置出发地和目的地)
return set_wp_origin_and_destination(origin, destination, terrain_alt);
}
位置:X:\ardupilot\libraries\AC_WPNav\AC_WPNav.cpp
/// set_origin_and_destination - set origin and destination waypoints using position vectors (distance from home in cm)
/// terrain_alt should be true if origin.z and destination.z are desired altitudes above terrain (false if these are alt-above-ekf-origin)
/// returns false on failure (likely caused by missing terrain data)
bool AC_WPNav::set_wp_origin_and_destination(const Vector3f& origin, const Vector3f& destination, bool terrain_alt)
{
// store origin and destination locations(存储源和目标位置)
_origin = origin;
_destination = destination;
_terrain_alt = terrain_alt;
Vector3f pos_delta = _destination - _origin;//位置之间的距离
_track_length = pos_delta.length(); // get track length(得到轨道长度)
_track_length_xy = safe_sqrt(sq(pos_delta.x)+sq(pos_delta.y)); // get horizontal track length (used to decide if we should update yaw)
// calculate each axis' percentage of the total distance to the destination(计算每个轴向目的地的总距离的百分比)
if (is_zero(_track_length)) {
// avoid possible divide by zero
_pos_delta_unit.x = 0;
_pos_delta_unit.y = 0;
_pos_delta_unit.z = 0;
}else{
_pos_delta_unit = pos_delta/_track_length;
}
// calculate leash lengths(计算刹车的长度)
calculate_wp_leash_length();
// get origin's alt-above-terrain
float origin_terr_offset = 0.0f;
if (terrain_alt) {
if (!get_terrain_offset(origin_terr_offset)) {
return false;
}
}
// initialise intermediate point to the origin(将中间点初始化到原点)
_pos_control.set_pos_target(origin + Vector3f(0,0,origin_terr_offset));
_track_desired = 0; // target is at beginning of track
_flags.reached_destination = false;
_flags.fast_waypoint = false; // default waypoint back to slow
_flags.slowing_down = false; // target is not slowing down yet
_flags.segment_type = SEGMENT_STRAIGHT;
_flags.new_wp_destination = true; // flag new waypoint so we can freeze the pos controller's feed forward and smooth the transition
_flags.wp_yaw_set = false;
// initialise the limited speed to current speed along the track(将有限的速度初始化到沿着轨道的速度)
const Vector3f &curr_vel = _inav.get_velocity();
// get speed along track (note: we convert vertical speed into horizontal speed equivalent)(沿着轨道加速(注意:我们将垂直速度转换为水平速度等效))
float speed_along_track = curr_vel.x * _pos_delta_unit.x + curr_vel.y * _pos_delta_unit.y + curr_vel.z * _pos_delta_unit.z;
_limited_speed_xy_cms = constrain_float(speed_along_track,0,_wp_speed_cms);// maximum horizontal speed in cm/s during missions
return true;
}
/// calculate_wp_leash_length - calculates horizontal and vertical leash lengths for waypoint controller(计算水平和垂直的刹车长度)
void AC_WPNav::calculate_wp_leash_length()
{
// length of the unit direction vector in the horizontal(水平方向矢量的长度)
float pos_delta_unit_xy = norm(_pos_delta_unit.x, _pos_delta_unit.y);
float pos_delta_unit_z = fabsf(_pos_delta_unit.z);
float speed_z;
float leash_z;
if (_pos_delta_unit.z >= 0.0f) {
speed_z = _wp_speed_up_cms;// climb speed target in cm/s
leash_z = _pos_control.get_leash_up_z();// vertical leash up in cm.
}else{
speed_z = _wp_speed_down_cms;// descent speed target in cm/s
leash_z = _pos_control.get_leash_down_z();// vertical leash down in cm.
}
// calculate the maximum acceleration, maximum velocity, and leash length in the direction of travel
if(is_zero(pos_delta_unit_z) && is_zero(pos_delta_unit_xy)){
_track_accel = 0;
_track_speed = 0;
_track_leash_length = WPNAV_LEASH_LENGTH_MIN;
}else if(is_zero(_pos_delta_unit.z)){//Z轴方向为0
_track_accel = _wp_accel_cms/pos_delta_unit_xy;
_track_speed = _wp_speed_cms/pos_delta_unit_xy;
_track_leash_length = _pos_control.get_leash_xy()/pos_delta_unit_xy;
}else if(is_zero(pos_delta_unit_xy)){//水平方向为0
_track_accel = _wp_accel_z_cms/pos_delta_unit_z;
_track_speed = speed_z/pos_delta_unit_z;
_track_leash_length = leash_z/pos_delta_unit_z;
}else{//两个方向都不为0,则取最小值
_track_accel = MIN(_wp_accel_z_cms/pos_delta_unit_z, _wp_accel_cms/pos_delta_unit_xy);
_track_speed = MIN(speed_z/pos_delta_unit_z, _wp_speed_cms/pos_delta_unit_xy);
_track_leash_length = MIN(leash_z/pos_delta_unit_z, _pos_control.get_leash_xy()/pos_delta_unit_xy);
}
// calculate slow down distance (the distance from the destination when the target point should begin to slow down)
calc_slow_down_distance(_track_speed, _track_accel);// speed in cm/s along track , acceleration along track
// set recalc leash flag to false
_flags.recalc_wp_leash = false;
}
/// calc_slow_down_distance - calculates distance before waypoint that target point should begin to slow-down assuming it is travelling at full speed
void AC_WPNav::calc_slow_down_distance(float speed_cms, float accel_cmss)
{
// protect against divide by zero
if (accel_cmss <= 0.0f) {
_slow_down_dist = 0.0f;
return;
}
// To-Do: should we use a combination of horizontal and vertical speeds?
// To-Do: update this automatically when speed or acceleration is changed
_slow_down_dist = speed_cms * speed_cms / (4.0f*accel_cmss);//这是什么公式?
}
位置:X:\ardupilot\libraries\AC_AttitudeControl\AC_PosControl.cpp
/// get_stopping_point_xy - calculates stopping point based on current position, velocity, vehicle acceleration
/// distance_max allows limiting distance to stopping point
/// results placed in stopping_position vector
/// set_accel_xy() should be called before this method to set vehicle acceleration
/// set_leash_length() should have been called before this method
void AC_PosControl::get_stopping_point_xy(Vector3f &stopping_point) const
{
const Vector3f curr_pos = _inav.get_position();//获取惯性导航的位置
Vector3f curr_vel = _inav.get_velocity();//获取惯性导航的速度
float linear_distance; // the distance at which we swap from a linear to sqrt response
float linear_velocity; // the velocity above which we swap from a linear to sqrt response
float stopping_dist; // the distance within the vehicle can stop
float kP = _p_pos_xy.kP();
// add velocity error to current velocity(将速度误差加到当前速度)
if (is_active_xy()) {//判断速度控制器是否活跃
curr_vel.x += _vel_error.x;
curr_vel.y += _vel_error.y;
}
// calculate current velocity(计算当前的速度)
float vel_total = norm(curr_vel.x, curr_vel.y);
// avoid divide by zero by using current position if the velocity is below 10cm/s, kP is very low or acceleration is zero
if (kP <= 0.0f || _accel_cms <= 0.0f || is_zero(vel_total)) {
stopping_point.x = curr_pos.x;
stopping_point.y = curr_pos.y;//设置当前点为停止点
return;
}
// calculate point at which velocity switches from linear to sqrt
linear_velocity = _accel_cms/kP;
// calculate distance within which we can stop(计算我们可以停止的距离)
if (vel_total < linear_velocity) {
stopping_dist = vel_total/kP;
} else {
linear_distance = _accel_cms/(2.0f*kP*kP);
stopping_dist = linear_distance + (vel_total*vel_total)/(2.0f*_accel_cms);
}
// constrain stopping distance
stopping_dist = constrain_float(stopping_dist, 0, _leash);
// convert the stopping distance into a stopping point using velocity vector
stopping_point.x = curr_pos.x + (stopping_dist * curr_vel.x / vel_total);
stopping_point.y = curr_pos.y + (stopping_dist * curr_vel.y / vel_total);//当前位置 + 停止距离
}
位置:X:\ardupilot\libraries\AC_AttitudeControl\AC_PosControl.cpp
/// get_stopping_point_z - calculates stopping point based on current position, velocity, vehicle acceleration
void AC_PosControl::get_stopping_point_z(Vector3f& stopping_point) const
{
const float curr_pos_z = _inav.get_altitude();//获取当前位置的高度
float curr_vel_z = _inav.get_velocity_z();//获取Z方向的速度
float linear_distance; // half the distance we swap between linear and sqrt and the distance we offset sqrt
float linear_velocity; // the velocity we swap between linear and sqrt
// if position controller is active add current velocity error to avoid sudden jump in acceleration
if (is_active_z()) {
curr_vel_z += _vel_error.z;
if (_flags.use_desvel_ff_z) {
curr_vel_z -= _vel_desired.z;
}
}
// avoid divide by zero by using current position if kP is very low or acceleration is zero
if (_p_pos_z.kP() <= 0.0f || _accel_z_cms <= 0.0f) {
stopping_point.z = curr_pos_z;//停止Z轴位置
return;
}
// calculate the velocity at which we switch from calculating the stopping point using a linear function to a sqrt function
// 计算我们从计算停止点的速度,使用一个线性函数到一个sqrt函数
linear_velocity = _accel_z_cms/_p_pos_z.kP();
if (fabsf(curr_vel_z) < linear_velocity) {
// if our current velocity is below the cross-over point we use a linear function
// 如果我们现在的速度低于交叉点我们使用一个线性函数
stopping_point.z = curr_pos_z + curr_vel_z/_p_pos_z.kP();//计算停止位置 = 当前位置 + 停止距离
} else {
linear_distance = _accel_z_cms/(2.0f*_p_pos_z.kP()*_p_pos_z.kP());
if (curr_vel_z > 0){
stopping_point.z = curr_pos_z + (linear_distance + curr_vel_z*curr_vel_z/(2.0f*_accel_z_cms));//计算停止位置 = 当前位置 + 停止距离
} else {
stopping_point.z = curr_pos_z - (linear_distance + curr_vel_z*curr_vel_z/(2.0f*_accel_z_cms));//计算停止位置 = 当前位置 + 停止距离
}
}
stopping_point.z = constrain_float(stopping_point.z, curr_pos_z - POSCONTROL_STOPPING_DIST_DOWN_MAX, curr_pos_z + POSCONTROL_STOPPING_DIST_UP_MAX);
}
// convert location to vector from ekf origin. terrain_alt is set to true if resulting vector's z-axis should be treated as alt-above-terrain
// returns false if conversion failed (likely because terrain data was not available)
bool AC_WPNav::get_vector_NEU(const Location_Class &loc, Vector3f &vec, bool &terrain_alt)
{
// convert location to NE vector2f
Vector2f res_vec;
if (!loc.get_vector_xy_from_origin_NE(res_vec)) {
return false;
}
// convert altitude
if (loc.get_alt_frame() == Location_Class::ALT_FRAME_ABOVE_TERRAIN) {
int32_t terr_alt;
if (!loc.get_alt_cm(Location_Class::ALT_FRAME_ABOVE_TERRAIN, terr_alt)) {
return false;
}
vec.z = terr_alt;
terrain_alt = true;
} else {
terrain_alt = false;
int32_t temp_alt;
if (!loc.get_alt_cm(Location_Class::ALT_FRAME_ABOVE_ORIGIN, temp_alt)) {
return false;
}
vec.z = temp_alt;
terrain_alt = false;
}
// copy xy (we do this to ensure we do not adjust vector unless the overall conversion is successful
vec.x = res_vec.x;
vec.y = res_vec.y;
return true;
}
位置:X:\ardupilot\libraries\AP_Common\Location.cpp
bool Location_Class::get_vector_xy_from_origin_NE(Vector2f &vec_ne) const
{
Location ekf_origin;
if (!_ahrs->get_origin(ekf_origin)) {
return false;
}
vec_ne.x = (lat-ekf_origin.lat) * LATLON_TO_CM;
vec_ne.y = (lng-ekf_origin.lng) * LATLON_TO_CM * longitude_scale(ekf_origin);//EAST值需要修正,用为纬度
return true;
}
位置:X:\ardupilot\libraries\AP_Math\location.cpp
float longitude_scale(const struct Location &loc)
{
float scale = cosf(loc.lat * 1.0e-7f * DEG_TO_RAD);//纬度值
return constrain_float(scale, 0.01f, 1.0f);
}
位置:X:\ardupilot\libraries\AC_WPNav\AC_WPNav.cpp
/// set_origin_and_destination - set origin and destination waypoints using position vectors (distance from home in cm)
/// terrain_alt should be true if origin.z and destination.z are desired altitudes above terrain (false if these are alt-above-ekf-origin)
/// returns false on failure (likely caused by missing terrain data)
bool AC_WPNav::set_wp_origin_and_destination(const Vector3f& origin, const Vector3f& destination, bool terrain_alt)
{
// store origin and destination locations
_origin = origin;
_destination = destination;
_terrain_alt = terrain_alt;
Vector3f pos_delta = _destination - _origin;
_track_length = pos_delta.length(); // get track length
_track_length_xy = safe_sqrt(sq(pos_delta.x)+sq(pos_delta.y)); // get horizontal track length (used to decide if we should update yaw)
// calculate each axis' percentage of the total distance to the destination
if (is_zero(_track_length)) {
// avoid possible divide by zero
_pos_delta_unit.x = 0;
_pos_delta_unit.y = 0;
_pos_delta_unit.z = 0;
}else{
_pos_delta_unit = pos_delta/_track_length;
}
// calculate leash lengths
calculate_wp_leash_length();
// get origin's alt-above-terrain
float origin_terr_offset = 0.0f;
if (terrain_alt) {
if (!get_terrain_offset(origin_terr_offset)) {
return false;
}
}
// initialise intermediate point to the origin
_pos_control.set_pos_target(origin + Vector3f(0,0,origin_terr_offset));
_track_desired = 0; // target is at beginning of track
_flags.reached_destination = false;
_flags.fast_waypoint = false; // default waypoint back to slow
_flags.slowing_down = false; // target is not slowing down yet
_flags.segment_type = SEGMENT_STRAIGHT;
_flags.new_wp_destination = true; // flag new waypoint so we can freeze the pos controller's feed forward and smooth the transition
_flags.wp_yaw_set = false;
// initialise the limited speed to current speed along the track
const Vector3f &curr_vel = _inav.get_velocity();
// get speed along track (note: we convert vertical speed into horizontal speed equivalent)
float speed_along_track = curr_vel.x * _pos_delta_unit.x + curr_vel.y * _pos_delta_unit.y + curr_vel.z * _pos_delta_unit.z;
_limited_speed_xy_cms = constrain_float(speed_along_track,0,_wp_speed_cms);
return true;
}
位置:X:\ardupilot\ArduCopter\mode.cpp
void Copter::Mode::set_auto_yaw_mode(uint8_t yaw_mode)
{
return copter.set_auto_yaw_mode(yaw_mode);
}
位置:X:\ardupilot\ArduCopter\mode_auto.cpp
// set_auto_yaw_mode - sets the yaw mode for auto
void Copter::set_auto_yaw_mode(uint8_t yaw_mode)
{
// return immediately if no change(跟原来模式相同的话,直接退出)
if (auto_yaw_mode == yaw_mode) {
return;
}
auto_yaw_mode = yaw_mode;
// perform initialisation
switch (auto_yaw_mode) {
case AUTO_YAW_LOOK_AT_NEXT_WP:
// wpnav will initialise heading when wpnav's set_destination method is called
break;
case AUTO_YAW_ROI:
// point towards a location held in yaw_look_at_WP
yaw_look_at_WP_bearing = ahrs.yaw_sensor;
break;
case AUTO_YAW_LOOK_AT_HEADING:
// keep heading pointing in the direction held in yaw_look_at_heading
// caller should set the yaw_look_at_heading
break;
case AUTO_YAW_LOOK_AHEAD:
// Commanded Yaw to automatically look ahead.
yaw_look_ahead_bearing = ahrs.yaw_sensor;
break;
case AUTO_YAW_RESETTOARMEDYAW:
// initial_armed_bearing will be set during arming so no init required
break;
case AUTO_YAW_RATE:
// initialise target yaw rate to zero
auto_yaw_rate_cds = 0.0f;
break;
}
}
// Autopilot Yaw Mode enumeration
enum autopilot_yaw_mode {
AUTO_YAW_HOLD = 0, // pilot controls the heading
AUTO_YAW_LOOK_AT_NEXT_WP = 1, // point towards next waypoint (no pilot input accepted)
AUTO_YAW_ROI = 2, // point towards a location held in roi_WP (no pilot input accepted)
AUTO_YAW_LOOK_AT_HEADING = 3, // point towards a particular angle (not pilot input accepted)
AUTO_YAW_LOOK_AHEAD = 4, // point in the direction the copter is moving
AUTO_YAW_RESETTOARMEDYAW = 5, // point towards heading at time motors were armed
AUTO_YAW_RATE = 6, // turn at a specified rate (held in auto_yaw_rate)
};
很水,只是记录阅读代码的过程。