mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
This is done to allow proper initialization of the new FlightTask and give it a chance to continue the setpoints without discontinuity. The function checkSetpoints replaces the setpoints containing NANs with an estimate of the state. The estimate is usually the current estimate of the EKF or zero. The transition FlightTask also provides an estimate of the current acceleration to properly initialize the next FlightTask after back-transition. This avoid having to initialize the accelerations to zero knowing that the actual acceleration is usually far from zero.
202 lines
4.9 KiB
C++
202 lines
4.9 KiB
C++
#include "FlightTasks.hpp"
|
|
|
|
#include <uORB/topics/vehicle_command.h>
|
|
#include <uORB/topics/vehicle_command_ack.h>
|
|
|
|
FlightTasks::FlightTasks()
|
|
{
|
|
// initialize all flight-tasks
|
|
// currently this is required to get all parameters read
|
|
for (int i = 0; i < static_cast<int>(FlightTaskIndex::Count); i++) {
|
|
_initTask(static_cast<FlightTaskIndex>(i));
|
|
}
|
|
|
|
// disable all tasks
|
|
_initTask(FlightTaskIndex::None);
|
|
}
|
|
|
|
bool FlightTasks::update()
|
|
{
|
|
_updateCommand();
|
|
|
|
if (isAnyTaskActive()) {
|
|
_subscription_array.update();
|
|
return _current_task.task->updateInitialize() && _current_task.task->update() && _current_task.task->updateFinalize();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const vehicle_local_position_setpoint_s FlightTasks::getPositionSetpoint()
|
|
{
|
|
if (isAnyTaskActive()) {
|
|
return _current_task.task->getPositionSetpoint();
|
|
|
|
} else {
|
|
return FlightTask::empty_setpoint;
|
|
}
|
|
}
|
|
|
|
const vehicle_constraints_s FlightTasks::getConstraints()
|
|
{
|
|
if (isAnyTaskActive()) {
|
|
return _current_task.task->getConstraints();
|
|
|
|
} else {
|
|
return FlightTask::empty_constraints;
|
|
}
|
|
}
|
|
|
|
const landing_gear_s FlightTasks::getGear()
|
|
{
|
|
if (isAnyTaskActive()) {
|
|
return _current_task.task->getGear();
|
|
|
|
} else {
|
|
return FlightTask::empty_landing_gear_default_keep;
|
|
}
|
|
}
|
|
|
|
int FlightTasks::switchTask(FlightTaskIndex new_task_index)
|
|
{
|
|
// switch to the running task, nothing to do
|
|
if (new_task_index == _current_task.index) {
|
|
return 0;
|
|
}
|
|
|
|
// Save current setpoints for the nex FlightTask
|
|
vehicle_local_position_setpoint_s current_state = getPositionSetpoint();
|
|
|
|
if (_initTask(new_task_index)) {
|
|
// invalid task
|
|
return -1;
|
|
}
|
|
|
|
if (!_current_task.task) {
|
|
// no task running
|
|
return 0;
|
|
}
|
|
|
|
// subscription failed
|
|
if (!_current_task.task->initializeSubscriptions(_subscription_array)) {
|
|
_current_task.task->~FlightTask();
|
|
_current_task.task = nullptr;
|
|
_current_task.index = FlightTaskIndex::None;
|
|
return -2;
|
|
}
|
|
|
|
_subscription_array.forcedUpdate(); // make sure data is available for all new subscriptions
|
|
|
|
// activation failed
|
|
if (!_current_task.task->updateInitialize() || !_current_task.task->activate(current_state)) {
|
|
_current_task.task->~FlightTask();
|
|
_current_task.task = nullptr;
|
|
_current_task.index = FlightTaskIndex::None;
|
|
return -3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int FlightTasks::switchTask(int new_task_index)
|
|
{
|
|
// make sure we are in range of the enumeration before casting
|
|
if (static_cast<int>(FlightTaskIndex::None) <= new_task_index &&
|
|
static_cast<int>(FlightTaskIndex::Count) > new_task_index) {
|
|
return switchTask(FlightTaskIndex(new_task_index));
|
|
}
|
|
|
|
switchTask(FlightTaskIndex::None);
|
|
return -1;
|
|
}
|
|
|
|
void FlightTasks::handleParameterUpdate()
|
|
{
|
|
if (isAnyTaskActive()) {
|
|
_current_task.task->handleParameterUpdate();
|
|
}
|
|
}
|
|
|
|
const char *FlightTasks::errorToString(const int error)
|
|
{
|
|
for (auto e : _taskError) {
|
|
if (e.error == error) {
|
|
return e.msg;
|
|
}
|
|
}
|
|
|
|
return "This error is not mapped to a string or is unknown.";
|
|
}
|
|
|
|
void FlightTasks::reActivate()
|
|
{
|
|
if (_current_task.task) {
|
|
_current_task.task->reActivate();
|
|
}
|
|
}
|
|
|
|
void FlightTasks::_updateCommand()
|
|
{
|
|
// lazy subscription to command topic
|
|
if (_sub_vehicle_command < 0) {
|
|
_sub_vehicle_command = orb_subscribe(ORB_ID(vehicle_command));
|
|
}
|
|
|
|
// check if there's any new command
|
|
bool updated = false;
|
|
orb_check(_sub_vehicle_command, &updated);
|
|
|
|
if (!updated) {
|
|
return;
|
|
}
|
|
|
|
// get command
|
|
struct vehicle_command_s command;
|
|
orb_copy(ORB_ID(vehicle_command), _sub_vehicle_command, &command);
|
|
|
|
// check what command it is
|
|
FlightTaskIndex desired_task = switchVehicleCommand(command.command);
|
|
|
|
if (desired_task == FlightTaskIndex::None) {
|
|
// ignore all unkown commands
|
|
return;
|
|
}
|
|
|
|
// switch to the commanded task
|
|
int switch_result = switchTask(desired_task);
|
|
uint8_t cmd_result = vehicle_command_ack_s::VEHICLE_RESULT_FAILED;
|
|
|
|
// if we are in/switched to the desired task
|
|
if (switch_result >= 0) {
|
|
cmd_result = vehicle_command_ack_s::VEHICLE_RESULT_ACCEPTED;
|
|
|
|
// if the task is running apply parameters to it and see if it rejects
|
|
if (isAnyTaskActive() && !_current_task.task->applyCommandParameters(command)) {
|
|
cmd_result = vehicle_command_ack_s::VEHICLE_RESULT_DENIED;
|
|
|
|
// if we just switched and parameters are not accepted, go to failsafe
|
|
if (switch_result == 1) {
|
|
switchTask(FlightTaskIndex::ManualPosition);
|
|
cmd_result = vehicle_command_ack_s::VEHICLE_RESULT_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
// send back acknowledgment
|
|
vehicle_command_ack_s command_ack = {};
|
|
command_ack.command = command.command;
|
|
command_ack.result = cmd_result;
|
|
command_ack.result_param1 = switch_result;
|
|
command_ack.target_system = command.source_system;
|
|
command_ack.target_component = command.source_component;
|
|
|
|
if (_pub_vehicle_command_ack == nullptr) {
|
|
_pub_vehicle_command_ack = orb_advertise_queue(ORB_ID(vehicle_command_ack), &command_ack,
|
|
vehicle_command_ack_s::ORB_QUEUE_LENGTH);
|
|
|
|
} else {
|
|
orb_publish(ORB_ID(vehicle_command_ack), _pub_vehicle_command_ack, &command_ack);
|
|
|
|
}
|
|
}
|