void MulticopterPositionControl::control_offboard(float dt) { bool updated; orb_check(_pos_sp_triplet_sub, &updated); if (updated) { orb_copy(ORB_ID(position_setpoint_triplet), _pos_sp_triplet_sub, &_pos_sp_triplet); } if (_pos_sp_triplet.current.valid) { if (_control_mode.flag_control_position_enabled && _pos_sp_triplet.current.position_valid) { /* control position */ _pos_sp(0) = _pos_sp_triplet.current.x; _pos_sp(1) = _pos_sp_triplet.current.y; } else if (_control_mode.flag_control_velocity_enabled && _pos_sp_triplet.current.velocity_valid) { /* control velocity */ /* reset position setpoint to current position if needed */ reset_pos_sp(); /* set position setpoint move rate */ _sp_move_rate(0) = _pos_sp_triplet.current.vx; _sp_move_rate(1) = _pos_sp_triplet.current.vy; } if (_pos_sp_triplet.current.yaw_valid) { _att_sp.yaw_body = _pos_sp_triplet.current.yaw; } else if (_pos_sp_triplet.current.yawspeed_valid) { _att_sp.yaw_body = _att_sp.yaw_body + _pos_sp_triplet.current.yawspeed * dt; } if (_control_mode.flag_control_altitude_enabled && _pos_sp_triplet.current.position_valid) { /* Control altitude */ _pos_sp(2) = _pos_sp_triplet.current.z; } else if (_control_mode.flag_control_climb_rate_enabled && _pos_sp_triplet.current.velocity_valid) { /* reset alt setpoint to current altitude if needed */ reset_alt_sp(); /* set altitude setpoint move rate */ _sp_move_rate(2) = _pos_sp_triplet.current.vz; } /* feed forward setpoint move rate with weight vel_ff */ _vel_ff = _sp_move_rate.emult(_params.vel_ff); /* move position setpoint */ _pos_sp += _sp_move_rate * dt; } else { reset_pos_sp(); reset_alt_sp(); } }
void MulticopterPositionControl::control_auto(float dt) { if (!_mode_auto) { _mode_auto = true; /* reset position setpoint on AUTO mode activation */ reset_pos_sp(); reset_alt_sp(); } //Poll position setpoint bool updated; orb_check(_pos_sp_triplet_sub, &updated); if (updated) { orb_copy(ORB_ID(position_setpoint_triplet), _pos_sp_triplet_sub, &_pos_sp_triplet); //Make sure that the position setpoint is valid if (!isfinite(_pos_sp_triplet.current.lat) || !isfinite(_pos_sp_triplet.current.lon) || !isfinite(_pos_sp_triplet.current.alt)) { _pos_sp_triplet.current.valid = false; } } if (_pos_sp_triplet.current.valid) { /* in case of interrupted mission don't go to waypoint but stay at current position */ _reset_pos_sp = true; _reset_alt_sp = true; /* project setpoint to local frame */ math::Vector<3> curr_sp; map_projection_project(&_ref_pos, _pos_sp_triplet.current.lat, _pos_sp_triplet.current.lon, &curr_sp.data[0], &curr_sp.data[1]); curr_sp(2) = -(_pos_sp_triplet.current.alt - _ref_alt); /* scaled space: 1 == position error resulting max allowed speed, L1 = 1 in this space */ math::Vector<3> scale = _params.pos_p.edivide(_params.vel_max); // TODO add mult param here /* convert current setpoint to scaled space */ math::Vector<3> curr_sp_s = curr_sp.emult(scale); /* by default use current setpoint as is */ math::Vector<3> pos_sp_s = curr_sp_s; if (_pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_POSITION && _pos_sp_triplet.previous.valid) { /* follow "previous - current" line */ math::Vector<3> prev_sp; map_projection_project(&_ref_pos, _pos_sp_triplet.previous.lat, _pos_sp_triplet.previous.lon, &prev_sp.data[0], &prev_sp.data[1]); prev_sp(2) = -(_pos_sp_triplet.previous.alt - _ref_alt); if ((curr_sp - prev_sp).length() > MIN_DIST) { /* find X - cross point of L1 sphere and trajectory */ math::Vector<3> pos_s = _pos.emult(scale); math::Vector<3> prev_sp_s = prev_sp.emult(scale); math::Vector<3> prev_curr_s = curr_sp_s - prev_sp_s; math::Vector<3> curr_pos_s = pos_s - curr_sp_s; float curr_pos_s_len = curr_pos_s.length(); if (curr_pos_s_len < 1.0f) { /* copter is closer to waypoint than L1 radius */ /* check next waypoint and use it to avoid slowing down when passing via waypoint */ if (_pos_sp_triplet.next.valid) { math::Vector<3> next_sp; map_projection_project(&_ref_pos, _pos_sp_triplet.next.lat, _pos_sp_triplet.next.lon, &next_sp.data[0], &next_sp.data[1]); next_sp(2) = -(_pos_sp_triplet.next.alt - _ref_alt); if ((next_sp - curr_sp).length() > MIN_DIST) { math::Vector<3> next_sp_s = next_sp.emult(scale); /* calculate angle prev - curr - next */ math::Vector<3> curr_next_s = next_sp_s - curr_sp_s; math::Vector<3> prev_curr_s_norm = prev_curr_s.normalized(); /* cos(a) * curr_next, a = angle between current and next trajectory segments */ float cos_a_curr_next = prev_curr_s_norm * curr_next_s; /* cos(b), b = angle pos - curr_sp - prev_sp */ float cos_b = -curr_pos_s * prev_curr_s_norm / curr_pos_s_len; if (cos_a_curr_next > 0.0f && cos_b > 0.0f) { float curr_next_s_len = curr_next_s.length(); /* if curr - next distance is larger than L1 radius, limit it */ if (curr_next_s_len > 1.0f) { cos_a_curr_next /= curr_next_s_len; } /* feed forward position setpoint offset */ math::Vector<3> pos_ff = prev_curr_s_norm * cos_a_curr_next * cos_b * cos_b * (1.0f - curr_pos_s_len) * (1.0f - expf(-curr_pos_s_len * curr_pos_s_len * 20.0f)); pos_sp_s += pos_ff; } } } } else { bool near = cross_sphere_line(pos_s, 1.0f, prev_sp_s, curr_sp_s, pos_sp_s); if (near) { /* L1 sphere crosses trajectory */ } else { /* copter is too far from trajectory */ /* if copter is behind prev waypoint, go directly to prev waypoint */ if ((pos_sp_s - prev_sp_s) * prev_curr_s < 0.0f) { pos_sp_s = prev_sp_s; } /* if copter is in front of curr waypoint, go directly to curr waypoint */ if ((pos_sp_s - curr_sp_s) * prev_curr_s > 0.0f) { pos_sp_s = curr_sp_s; } pos_sp_s = pos_s + (pos_sp_s - pos_s).normalized(); } } } } /* move setpoint not faster than max allowed speed */ math::Vector<3> pos_sp_old_s = _pos_sp.emult(scale); /* difference between current and desired position setpoints, 1 = max speed */ math::Vector<3> d_pos_m = (pos_sp_s - pos_sp_old_s).edivide(_params.pos_p); float d_pos_m_len = d_pos_m.length(); if (d_pos_m_len > dt) { pos_sp_s = pos_sp_old_s + (d_pos_m / d_pos_m_len * dt).emult(_params.pos_p); } /* scale result back to normal space */ _pos_sp = pos_sp_s.edivide(scale); /* update yaw setpoint if needed */ if (isfinite(_pos_sp_triplet.current.yaw)) { _att_sp.yaw_body = _pos_sp_triplet.current.yaw; } } else { /* no waypoint, do nothing, setpoint was already reset */ } }
void MulticopterPositionControl::control_manual(float dt) { _sp_move_rate.zero(); if (_control_mode.flag_control_altitude_enabled) { if(_reset_mission) { _reset_mission = false; _mode_mission = 1 ; _hover_time = 0.0 ; } float height_hover_constant=-1.0; float hover_time_constant = 20.0; switch(_mode_mission) { case 1: _sp_move_rate(2) = -0.8; if(_pos_sp(2)<=height_hover_constant) _mode_mission=2; break; case 2: _hover_time += dt; if(_hover_time>hover_time_constant) { _hover_time=0.0; _mode_mission=3; } break; case 3: _pos_sp_triplet.current.type =position_setpoint_s::SETPOINT_TYPE_LAND; break; default: /* move altitude setpoint with throttle stick */ _sp_move_rate(2) = -scale_control(_manual.z - 0.5f, 0.5f, alt_ctl_dz); break; } } if (_control_mode.flag_control_position_enabled) { /* move position setpoint with roll/pitch stick */ _sp_move_rate(0) = _manual.x; _sp_move_rate(1) = _manual.y; } /* limit setpoint move rate */ float sp_move_norm = _sp_move_rate.length(); if (sp_move_norm > 1.0f) { _sp_move_rate /= sp_move_norm; } /* _sp_move_rate scaled to 0..1, scale it to max speed and rotate around yaw */ math::Matrix<3, 3> R_yaw_sp; R_yaw_sp.from_euler(0.0f, 0.0f, _att_sp.yaw_body); _sp_move_rate = R_yaw_sp * _sp_move_rate.emult(_params.vel_max); if (_control_mode.flag_control_altitude_enabled) { /* reset alt setpoint to current altitude if needed */ reset_alt_sp(); } if (_control_mode.flag_control_position_enabled) { /* reset position setpoint to current position if needed */ reset_pos_sp(); } /* feed forward setpoint move rate with weight vel_ff */ _vel_ff = _sp_move_rate.emult(_params.vel_ff); /* move position setpoint */ _pos_sp += _sp_move_rate * dt; /* check if position setpoint is too far from actual position */ math::Vector<3> pos_sp_offs; pos_sp_offs.zero(); if (_control_mode.flag_control_position_enabled) { pos_sp_offs(0) = (_pos_sp(0) - _pos(0)) / _params.sp_offs_max(0); pos_sp_offs(1) = (_pos_sp(1) - _pos(1)) / _params.sp_offs_max(1); } if (_control_mode.flag_control_altitude_enabled) { pos_sp_offs(2) = (_pos_sp(2) - _pos(2)) / _params.sp_offs_max(2); } float pos_sp_offs_norm = pos_sp_offs.length(); if (pos_sp_offs_norm > 1.0f) { pos_sp_offs /= pos_sp_offs_norm; _pos_sp = _pos + pos_sp_offs.emult(_params.sp_offs_max); } }
void MulticopterPositionControl::control_manual(float dt) { _sp_move_rate.zero(); if (_control_mode.flag_control_altitude_enabled) { /* move altitude setpoint with throttle stick */ _sp_move_rate(2) = -scale_control(_manual.z - 0.5f, 0.5f, alt_ctl_dz); } if (_control_mode.flag_control_position_enabled) { /* move position setpoint with roll/pitch stick */ _sp_move_rate(0) = _manual.x; _sp_move_rate(1) = _manual.y; } /* limit setpoint move rate */ float sp_move_norm = _sp_move_rate.length(); if (sp_move_norm > 1.0f) { _sp_move_rate /= sp_move_norm; } /* _sp_move_rate scaled to 0..1, scale it to max speed and rotate around yaw */ math::Matrix<3, 3> R_yaw_sp; R_yaw_sp.from_euler(0.0f, 0.0f, _att_sp.yaw_body); _sp_move_rate = R_yaw_sp * _sp_move_rate.emult(_params.vel_max); if (_control_mode.flag_control_altitude_enabled) { /* reset alt setpoint to current altitude if needed */ reset_alt_sp(); } if (_control_mode.flag_control_position_enabled) { /* reset position setpoint to current position if needed */ reset_pos_sp(); } /* feed forward setpoint move rate with weight vel_ff */ _vel_ff = _sp_move_rate.emult(_params.vel_ff); /* move position setpoint */ _pos_sp += _sp_move_rate * dt; /* check if position setpoint is too far from actual position */ math::Vector<3> pos_sp_offs; pos_sp_offs.zero(); if (_control_mode.flag_control_position_enabled) { pos_sp_offs(0) = (_pos_sp(0) - _pos(0)) / _params.sp_offs_max(0); pos_sp_offs(1) = (_pos_sp(1) - _pos(1)) / _params.sp_offs_max(1); } if (_control_mode.flag_control_altitude_enabled) { pos_sp_offs(2) = (_pos_sp(2) - _pos(2)) / _params.sp_offs_max(2); } float pos_sp_offs_norm = pos_sp_offs.length(); if (pos_sp_offs_norm > 1.0f) { pos_sp_offs /= pos_sp_offs_norm; _pos_sp = _pos + pos_sp_offs.emult(_params.sp_offs_max); } }