void AC_WPNav::set_spline_dest_and_vel(const Vector3f& dest_pos, const Vector3f& dest_vel) { // check _wp_accel_cms is reasonable to avoid divide by zero if (_wp_accel_cms <= 0) { _wp_accel_cms.set_and_save(WPNAV_ACCELERATION); } _spline_time = 0.0f; _origin = _inav.get_position(); _destination = dest_pos; _spline_origin_vel = _inav.get_velocity(); _spline_destination_vel = dest_vel; if(_spline_origin_vel.length() < 100.0f) { _spline_origin_vel = (_destination - _origin) * 0.1f; } _spline_vel_scaler = _spline_origin_vel.length(); _flags.fast_waypoint = _spline_destination_vel.length() > 0.0f; float vel_len = (_spline_origin_vel + _spline_destination_vel).length(); float pos_len = (_destination - _origin).length() * 4.0f; if (vel_len > pos_len) { // if total start+stop velocity is more than twice position difference // use a scaled down start and stop velocityscale the start and stop velocities down float vel_scaling = pos_len / vel_len; // update spline calculator update_spline_solution(_origin, _destination, _spline_origin_vel * vel_scaling, _spline_destination_vel * vel_scaling); } else { // update spline calculator update_spline_solution(_origin, _destination, _spline_origin_vel, _spline_destination_vel); } // initialise yaw heading to current heading _yaw = _attitude_control.angle_ef_targets().z; // calculate slow down distance calc_slow_down_distance(_wp_speed_cms, _wp_accel_cms); // initialise intermediate point to the origin _pos_control.set_pos_target(_origin); _flags.reached_destination = false; _flags.segment_type = SEGMENT_SPLINE; _flags.new_wp_destination = true; // flag new waypoint so we can freeze the pos controller's feed forward and smooth the transition }
/// set_spline_origin_and_destination - set origin and destination waypoints using position vectors (distance from home in cm) /// seg_type should be calculated by calling function based on the mission void AC_WPNav::set_spline_origin_and_destination(const Vector3f& origin, const Vector3f& destination, bool stopped_at_start, spline_segment_end_type seg_end_type, const Vector3f& next_destination) { // mission is "active" if wpnav has been called recently and vehicle reached the previous waypoint bool prev_segment_exists = (_flags.reached_destination && ((hal.scheduler->millis() - _wp_last_update) < 1000)); // check _wp_accel_cms is reasonable to avoid divide by zero if (_wp_accel_cms <= 0) { _wp_accel_cms.set_and_save(WPNAV_ACCELERATION); } // segment start types // stop - vehicle is not moving at origin // straight-fast - vehicle is moving, previous segment is straight. vehicle will fly straight through the waypoint before beginning it's spline path to the next wp // _flag.segment_type holds whether prev segment is straight vs spline but we don't know if it has a delay // spline-fast - vehicle is moving, previous segment is splined, vehicle will fly through waypoint but previous segment should have it flying in the correct direction (i.e. exactly parallel to position difference vector from previous segment's origin to this segment's destination) // calculate spline velocity at origin if (stopped_at_start || !prev_segment_exists) { // if vehicle is stopped at the origin, set origin velocity to 0.1 * distance vector from origin to destination _spline_origin_vel = (destination - origin) * 0.1f; _spline_time = 0.0f; _spline_vel_scaler = 0.0f; }else{ // look at previous segment to determine velocity at origin if (_flags.segment_type == SEGMENT_STRAIGHT) { // previous segment is straight, vehicle is moving so vehicle should fly straight through the origin // before beginning it's spline path to the next waypoint. Note: we are using the previous segment's origin and destination _spline_origin_vel = (_destination - _origin); _spline_time = 0.0f; // To-Do: this should be set based on how much overrun there was from straight segment? _spline_vel_scaler = 0.0f; // To-Do: this should be set based on speed at end of prev straight segment? }else{ // previous segment is splined, vehicle will fly through origin // we can use the previous segment's destination velocity as this segment's origin velocity // Note: previous segment will leave destination velocity parallel to position difference vector // from previous segment's origin to this segment's destination) _spline_origin_vel = _spline_destination_vel; if (_spline_time > 1.0f && _spline_time < 1.1f) { // To-Do: remove hard coded 1.1f _spline_time -= 1.0f; }else{ _spline_time = 0.0f; } _spline_vel_scaler = 0.0f; } } // calculate spline velocity at destination switch (seg_end_type) { case SEGMENT_END_STOP: // if vehicle stops at the destination set destination velocity to 0.1 * distance vector from origin to destination _spline_destination_vel = (destination - origin) * 0.1f; _flags.fast_waypoint = false; break; case SEGMENT_END_STRAIGHT: // if next segment is straight, vehicle's final velocity should face along the next segment's position _spline_destination_vel = (next_destination - destination); _flags.fast_waypoint = true; break; case SEGMENT_END_SPLINE: // if next segment is splined, vehicle's final velocity should face parallel to the line from the origin to the next destination _spline_destination_vel = (next_destination - origin); _flags.fast_waypoint = true; break; } // code below ensures we don't get too much overshoot when the next segment is short float vel_len = (_spline_origin_vel + _spline_destination_vel).length(); float pos_len = (destination - origin).length() * 4.0f; if (vel_len > pos_len) { // if total start+stop velocity is more than twice position difference // use a scaled down start and stop velocityscale the start and stop velocities down float vel_scaling = pos_len / vel_len; // update spline calculator update_spline_solution(origin, destination, _spline_origin_vel * vel_scaling, _spline_destination_vel * vel_scaling); }else{ // update spline calculator update_spline_solution(origin, destination, _spline_origin_vel, _spline_destination_vel); } // initialise yaw heading to current heading _yaw = _ahrs->yaw_sensor; // store origin and destination locations _origin = origin; _destination = destination; // initialise position controller speed and acceleration _pos_control.set_speed_xy(_wp_speed_cms); _pos_control.set_accel_xy(_wp_accel_cms); _pos_control.set_speed_z(-_wp_speed_down_cms, _wp_speed_up_cms); _pos_control.calc_leash_length_xy(); _pos_control.calc_leash_length_z(); // calculate leash lengths calculate_wp_leash_length(); // calculate slow down distance // To-Do: this should be used for straight segments as well // To-Do: should we use a combination of horizontal and vertical speeds? // To-Do: update this automatically when speed or acceleration is changed _spline_slow_down_dist = _wp_speed_cms * _wp_speed_cms / (2.0f*_wp_accel_cms); // initialise intermediate point to the origin _pos_control.set_pos_target(origin); _flags.reached_destination = false; _flags.segment_type = SEGMENT_SPLINE; }
/// set_spline_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 desired altitudes above ekf origin) /// seg_type should be calculated by calling function based on the mission bool AC_WPNav::set_spline_origin_and_destination(const Vector3f& origin, const Vector3f& destination, bool terrain_alt, bool stopped_at_start, spline_segment_end_type seg_end_type, const Vector3f& next_destination) { // mission is "active" if wpnav has been called recently and vehicle reached the previous waypoint bool prev_segment_exists = (_flags.reached_destination && ((AP_HAL::millis() - _wp_last_update) < 1000)); float dt = _pos_control.get_dt_xy(); // check _wp_accel_cms is reasonable to avoid divide by zero if (_wp_accel_cms <= 0) { _wp_accel_cms.set_and_save(WPNAV_ACCELERATION); } // segment start types // stop - vehicle is not moving at origin // straight-fast - vehicle is moving, previous segment is straight. vehicle will fly straight through the waypoint before beginning it's spline path to the next wp // _flag.segment_type holds whether prev segment is straight vs spline but we don't know if it has a delay // spline-fast - vehicle is moving, previous segment is splined, vehicle will fly through waypoint but previous segment should have it flying in the correct direction (i.e. exactly parallel to position difference vector from previous segment's origin to this segment's destination) // calculate spline velocity at origin if (stopped_at_start || !prev_segment_exists) { // if vehicle is stopped at the origin, set origin velocity to 0.02 * distance vector from origin to destination _spline_origin_vel = (destination - origin) * dt; _spline_time = 0.0f; _spline_vel_scaler = 0.0f; }else{ // look at previous segment to determine velocity at origin if (_flags.segment_type == SEGMENT_STRAIGHT) { // previous segment is straight, vehicle is moving so vehicle should fly straight through the origin // before beginning it's spline path to the next waypoint. Note: we are using the previous segment's origin and destination _spline_origin_vel = (_destination - _origin); _spline_time = 0.0f; // To-Do: this should be set based on how much overrun there was from straight segment? _spline_vel_scaler = _pos_control.get_vel_target().length(); // start velocity target from current target velocity }else{ // previous segment is splined, vehicle will fly through origin // we can use the previous segment's destination velocity as this segment's origin velocity // Note: previous segment will leave destination velocity parallel to position difference vector // from previous segment's origin to this segment's destination) _spline_origin_vel = _spline_destination_vel; if (_spline_time > 1.0f && _spline_time < 1.1f) { // To-Do: remove hard coded 1.1f _spline_time -= 1.0f; }else{ _spline_time = 0.0f; } // Note: we leave _spline_vel_scaler as it was from end of previous segment } } // calculate spline velocity at destination switch (seg_end_type) { case SEGMENT_END_STOP: // if vehicle stops at the destination set destination velocity to 0.02 * distance vector from origin to destination _spline_destination_vel = (destination - origin) * dt; _flags.fast_waypoint = false; break; case SEGMENT_END_STRAIGHT: // if next segment is straight, vehicle's final velocity should face along the next segment's position _spline_destination_vel = (next_destination - destination); _flags.fast_waypoint = true; break; case SEGMENT_END_SPLINE: // if next segment is splined, vehicle's final velocity should face parallel to the line from the origin to the next destination _spline_destination_vel = (next_destination - origin); _flags.fast_waypoint = true; break; } // code below ensures we don't get too much overshoot when the next segment is short float vel_len = _spline_origin_vel.length() + _spline_destination_vel.length(); float pos_len = (destination - origin).length() * 4.0f; if (vel_len > pos_len) { // if total start+stop velocity is more than twice position difference // use a scaled down start and stop velocityscale the start and stop velocities down float vel_scaling = pos_len / vel_len; // update spline calculator update_spline_solution(origin, destination, _spline_origin_vel * vel_scaling, _spline_destination_vel * vel_scaling); }else{ // update spline calculator update_spline_solution(origin, destination, _spline_origin_vel, _spline_destination_vel); } // initialise yaw heading to current heading _yaw = _attitude_control.get_att_target_euler_cd().z; // store origin and destination locations _origin = origin; _destination = destination; _terrain_alt = terrain_alt; // calculate slow down distance calc_slow_down_distance(_wp_speed_cms, _wp_accel_cms); // get alt-above-terrain float terr_offset = 0.0f; if (terrain_alt) { if (!get_terrain_offset(terr_offset)) { return false; } } // initialise intermediate point to the origin _pos_control.set_pos_target(origin + Vector3f(0,0,terr_offset)); _flags.reached_destination = false; _flags.segment_type = SEGMENT_SPLINE; _flags.new_wp_destination = true; // flag new waypoint so we can freeze the pos controller's feed forward and smooth the transition return true; }