Files
bizhang_-obav/src/modules/commander/commander.cpp

3501 lines
120 KiB
C++
Raw Normal View History

/****************************************************************************
*
* Copyright (c) 2013-2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file commander.cpp
* Main fail-safe handling.
2012-10-23 13:15:36 +02:00
*
* @author Petri Tanskanen <petri.tanskanen@inf.ethz.ch>
* @author Lorenz Meier <lorenz@px4.io>
2015-05-17 12:58:44 +02:00
* @author Thomas Gubler <thomas@px4.io>
* @author Julian Oes <julian@px4.io>
* @author Anton Babushkin <anton@px4.io>
*/
#include <px4_config.h>
#include <px4_posix.h>
#include <px4_time.h>
2015-09-11 21:48:36 +02:00
#include <px4_tasks.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <systemlib/err.h>
#include <systemlib/circuit_breaker.h>
//#include <debug.h>
#include <sys/stat.h>
#include <string.h>
#include <math.h>
#include <poll.h>
#include <float.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/battery_status.h>
#include <uORB/topics/manual_control_setpoint.h>
#include <uORB/topics/offboard_control_mode.h>
#include <uORB/topics/home_position.h>
#include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/position_setpoint_triplet.h>
#include <uORB/topics/vehicle_gps_position.h>
#include <uORB/topics/vehicle_command.h>
#include <uORB/topics/subsystem_info.h>
#include <uORB/topics/actuator_controls.h>
2015-01-25 13:39:34 +01:00
#include <uORB/topics/actuator_controls_0.h>
#include <uORB/topics/actuator_controls_1.h>
#include <uORB/topics/actuator_controls_2.h>
#include <uORB/topics/actuator_controls_3.h>
#include <uORB/topics/actuator_armed.h>
#include <uORB/topics/parameter_update.h>
2013-02-24 21:57:38 +01:00
#include <uORB/topics/differential_pressure.h>
#include <uORB/topics/safety.h>
#include <uORB/topics/system_power.h>
#include <uORB/topics/mission.h>
#include <uORB/topics/mission_result.h>
#include <uORB/topics/geofence_result.h>
#include <uORB/topics/telemetry_status.h>
#include <uORB/topics/vtol_vehicle_status.h>
2015-05-17 12:58:44 +02:00
#include <uORB/topics/vehicle_land_detected.h>
#include <uORB/topics/input_rc.h>
2015-12-12 13:01:49 +01:00
#include <uORB/topics/vehicle_command_ack.h>
#include <drivers/drv_led.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_tone_alarm.h>
#include <mavlink/mavlink_log.h>
#include <systemlib/param/param.h>
#include <systemlib/systemlib.h>
#include <systemlib/err.h>
#include <systemlib/cpuload.h>
#include <systemlib/rc_check.h>
#include <geo/geo.h>
#include <systemlib/state_table.h>
#include <dataman/dataman.h>
#include <navigator/navigation.h>
#include "px4_custom_mode.h"
#include "commander_helper.h"
#include "state_machine_helper.h"
#include "calibration_routines.h"
#include "accelerometer_calibration.h"
#include "gyro_calibration.h"
#include "mag_calibration.h"
#include "baro_calibration.h"
#include "rc_calibration.h"
#include "airspeed_calibration.h"
2015-04-28 14:54:58 +02:00
#include "esc_calibration.h"
#include "PreflightCheck.h"
/* oddly, ERROR is not defined for c++ */
#ifdef ERROR
# undef ERROR
#endif
static const int ERROR = -1;
extern struct system_load_s system_load;
static constexpr uint8_t COMMANDER_MAX_GPS_NOISE = 60; /**< Maximum percentage signal to noise ratio allowed for GPS reception */
/* Decouple update interval and hysteris counters, all depends on intervals */
#define COMMANDER_MONITORING_INTERVAL 50000
#define COMMANDER_MONITORING_LOOPSPERMSEC (1/(COMMANDER_MONITORING_INTERVAL/1000.0f))
#define MAVLINK_OPEN_INTERVAL 50000
#define STICK_ON_OFF_LIMIT 0.9f
#define STICK_ON_OFF_HYSTERESIS_TIME_MS 1000
#define STICK_ON_OFF_COUNTER_LIMIT (STICK_ON_OFF_HYSTERESIS_TIME_MS*COMMANDER_MONITORING_LOOPSPERMSEC)
#define POSITION_TIMEOUT (1 * 1000 * 1000) /**< consider the local or global position estimate invalid after 1000ms */
#define FAILSAFE_DEFAULT_TIMEOUT (3 * 1000 * 1000) /**< hysteresis time - the failsafe will trigger after 3 seconds in this state */
2014-05-16 12:12:43 +02:00
#define OFFBOARD_TIMEOUT 500000
#define DIFFPRESS_TIMEOUT 2000000
#define HOTPLUG_SENS_TIMEOUT (8 * 1000 * 1000) /**< wait for hotplug sensors to come online for upto 10 seconds */
#define PRINT_INTERVAL 5000000
#define PRINT_MODE_REJECT_INTERVAL 10000000
#define INAIR_RESTART_HOLDOFF_INTERVAL 500000
#define HIL_ID_MIN 1000
#define HIL_ID_MAX 1999
enum MAV_MODE_FLAG {
MAV_MODE_FLAG_CUSTOM_MODE_ENABLED = 1, /* 0b00000001 Reserved for future use. | */
MAV_MODE_FLAG_TEST_ENABLED = 2, /* 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | */
MAV_MODE_FLAG_AUTO_ENABLED = 4, /* 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | */
MAV_MODE_FLAG_GUIDED_ENABLED = 8, /* 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | */
MAV_MODE_FLAG_STABILIZE_ENABLED = 16, /* 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | */
MAV_MODE_FLAG_HIL_ENABLED = 32, /* 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | */
MAV_MODE_FLAG_MANUAL_INPUT_ENABLED = 64, /* 0b01000000 remote control input is enabled. | */
MAV_MODE_FLAG_SAFETY_ARMED = 128, /* 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. | */
MAV_MODE_FLAG_ENUM_END = 129, /* | */
};
/* Mavlink file descriptors */
static int mavlink_fd = 0;
/* System autostart ID */
static int autostart_id;
/* flags */
static bool commander_initialized = false;
2015-03-23 10:52:32 -07:00
static volatile bool thread_should_exit = false; /**< daemon exit flag */
static volatile bool thread_running = false; /**< daemon status flag */
2015-03-23 10:52:32 -07:00
static int daemon_task; /**< Handle of daemon task / thread */
static bool need_param_autosave = false; /**< Flag set to true if parameters should be autosaved in next iteration (happens on param update and if functionality is enabled) */
2015-11-04 18:23:19 +01:00
static bool _usb_telemetry_active = false;
static hrt_abstime commander_boot_timestamp = 0;
static unsigned int leds_counter;
/* To remember when last notification was sent */
static uint64_t last_print_mode_reject_time = 0;
static uint64_t _inair_last_time = 0;
static float eph_threshold = 5.0f;
static float epv_threshold = 10.0f;
static struct vehicle_status_s status;
static struct actuator_armed_s armed;
static struct safety_s safety;
2014-01-30 17:23:10 +01:00
static struct vehicle_control_mode_s control_mode;
static struct offboard_control_mode_s offboard_control_mode;
2015-06-08 15:19:41 +02:00
static struct home_position_s _home;
2015-06-13 18:37:19 +02:00
static unsigned _last_mission_instance = 0;
2015-09-27 19:49:01 -04:00
static manual_control_setpoint_s _last_sp_man;
2015-06-13 18:37:19 +02:00
2015-11-04 18:23:19 +01:00
static struct vtol_vehicle_status_s vtol_status;
/**
2013-07-16 09:35:31 +02:00
* The daemon app only briefly exists to start
* the background job. The stack size assigned in the
* Makefile does only apply to this management task.
*
* The actual stack size should be set in the call
* to task_create().
*
* @ingroup apps
*/
extern "C" __EXPORT int commander_main(int argc, char *argv[]);
/**
2013-07-16 09:35:31 +02:00
* Print the correct usage.
*/
2013-07-16 09:35:31 +02:00
void usage(const char *reason);
/**
* React to commands that are sent e.g. from the mavlink module.
*/
bool handle_command(struct vehicle_status_s *status, const struct safety_s *safety, struct vehicle_command_s *cmd,
struct actuator_armed_s *armed, struct home_position_s *home, struct vehicle_global_position_s *global_pos,
2015-12-12 13:01:49 +01:00
struct vehicle_local_position_s *local_pos, struct vehicle_attitude_s *attitude, orb_advert_t *home_pub,
orb_advert_t *command_ack_pub, struct vehicle_command_ack_s *command_ack);
/**
2013-07-16 09:35:31 +02:00
* Mainloop of commander.
*/
2013-07-16 09:35:31 +02:00
int commander_thread_main(int argc, char *argv[]);
void control_status_leds(vehicle_status_s *status, const actuator_armed_s *actuator_armed, bool changed);
2013-08-27 23:08:00 +02:00
void get_circuit_breaker_params();
void check_valid(hrt_abstime timestamp, hrt_abstime timeout, bool valid_in, bool *valid_out, bool *changed);
transition_result_t set_main_state_rc(struct vehicle_status_s *status, struct manual_control_setpoint_s *sp_man);
2013-07-28 23:12:16 +04:00
void set_control_mode();
bool stabilization_required();
void print_reject_mode(struct vehicle_status_s *current_status, const char *msg);
2013-08-27 23:08:00 +02:00
void print_reject_arm(const char *msg);
void print_status();
transition_result_t check_navigation_state_machine(struct vehicle_status_s *status,
struct vehicle_control_mode_s *control_mode, struct vehicle_local_position_s *local_pos);
2014-05-11 13:36:51 +02:00
transition_result_t arm_disarm(bool arm, const int mavlink_fd, const char *armedBy);
/**
* @brief This function initializes the home position of the vehicle. This happens first time we get a good GPS fix and each
* time the vehicle is armed with a good GPS fix.
**/
2015-01-16 16:46:16 +01:00
static void commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
const vehicle_local_position_s &localPosition, const vehicle_global_position_s &globalPosition,
const vehicle_attitude_s &attitude);
2013-07-16 09:35:31 +02:00
/**
* Loop that runs at a lower rate and priority for calibration and parameter tasks.
*/
void *commander_low_prio_loop(void *arg);
2015-12-12 13:01:49 +01:00
void answer_command(struct vehicle_command_s &cmd, unsigned result,
orb_advert_t &command_ack_pub, vehicle_command_ack_s &command_ack);
2013-08-27 23:08:00 +02:00
2015-06-10 11:05:56 -06:00
/**
* check whether autostart ID is in the reserved range for HIL setups
*/
bool is_hil_setup(int id);
bool is_hil_setup(int id) {
return (id >= HIL_ID_MIN) && (id <= HIL_ID_MAX);
}
2013-07-16 09:35:31 +02:00
int commander_main(int argc, char *argv[])
{
if (argc < 2) {
2013-07-16 09:35:31 +02:00
usage("missing command");
return 1;
2014-05-11 13:36:51 +02:00
}
2013-07-16 09:35:31 +02:00
if (!strcmp(argv[1], "start")) {
if (thread_running) {
warnx("already running");
2013-07-16 09:35:31 +02:00
/* this is not an error */
return 0;
2013-07-16 09:35:31 +02:00
}
thread_should_exit = false;
daemon_task = px4_task_spawn_cmd("commander",
2013-07-28 23:12:16 +04:00
SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT + 40,
3600,
2013-07-28 23:12:16 +04:00
commander_thread_main,
2015-08-26 16:17:07 +02:00
(char * const *)&argv[0]);
unsigned constexpr max_wait_us = 1000000;
unsigned constexpr max_wait_steps = 2000;
unsigned i;
for (i = 0; i < max_wait_steps; i++) {
usleep(max_wait_us / max_wait_steps);
if (thread_running) {
break;
}
}
2015-08-11 11:03:01 +02:00
return !(i < max_wait_steps);
2013-07-16 09:35:31 +02:00
}
2013-07-16 09:35:31 +02:00
if (!strcmp(argv[1], "stop")) {
2014-05-11 13:36:51 +02:00
if (!thread_running) {
warnx("commander already stopped");
return 0;
2014-05-11 13:36:51 +02:00
}
2013-07-16 09:35:31 +02:00
thread_should_exit = true;
while (thread_running) {
usleep(200000);
warnx(".");
}
warnx("terminated.");
return 0;
2013-07-16 09:35:31 +02:00
}
/* commands needing the app to run below */
if (!thread_running) {
warnx("\tcommander not started");
return 1;
}
2013-07-16 09:35:31 +02:00
if (!strcmp(argv[1], "status")) {
print_status();
return 0;
}
2013-07-16 09:35:31 +02:00
if (!strcmp(argv[1], "calibrate")) {
if (argc > 2) {
int calib_ret = OK;
if (!strcmp(argv[2], "mag")) {
calib_ret = do_mag_calibration(mavlink_fd);
} else if (!strcmp(argv[2], "accel")) {
calib_ret = do_accel_calibration(mavlink_fd);
} else if (!strcmp(argv[2], "gyro")) {
calib_ret = do_gyro_calibration(mavlink_fd);
} else if (!strcmp(argv[2], "level")) {
calib_ret = do_level_calibration(mavlink_fd);
2015-05-22 09:28:52 -07:00
} else if (!strcmp(argv[2], "esc")) {
calib_ret = do_esc_calibration(mavlink_fd, &armed);
2015-11-17 12:59:45 +01:00
} else if (!strcmp(argv[2], "airspeed")) {
calib_ret = do_airspeed_calibration(mavlink_fd);
} else {
warnx("argument %s unsupported.", argv[2]);
}
if (calib_ret) {
warnx("calibration failed, exiting.");
2015-08-26 16:17:07 +02:00
return 1;
} else {
return 0;
}
} else {
warnx("missing argument");
}
}
if (!strcmp(argv[1], "check")) {
2015-06-22 09:58:01 +02:00
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
int checkres = 0;
checkres = preflight_check(&status, mavlink_fd_local, false, true);
warnx("Preflight check: %s", (checkres == 0) ? "OK" : "FAILED");
checkres = preflight_check(&status, mavlink_fd_local, true, true);
warnx("Prearm check: %s", (checkres == 0) ? "OK" : "FAILED");
px4_close(mavlink_fd_local);
return 0;
2013-07-16 09:35:31 +02:00
}
if (!strcmp(argv[1], "arm")) {
2015-06-22 09:58:01 +02:00
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
2015-12-20 20:29:22 +01:00
if (TRANSITION_CHANGED != arm_disarm(true, mavlink_fd_local, "command line")) {
warnx("arming failed");
}
px4_close(mavlink_fd_local);
return 0;
}
2014-07-11 14:55:46 +02:00
if (!strcmp(argv[1], "disarm")) {
2015-06-22 09:58:01 +02:00
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
if (TRANSITION_DENIED == arm_disarm(false, mavlink_fd_local, "command line")) {
warnx("rejected disarm");
}
px4_close(mavlink_fd_local);
2015-08-26 16:17:07 +02:00
return 0;
}
if (!strcmp(argv[1], "takeoff")) {
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
2015-12-20 20:29:22 +01:00
/* see if we got a home position */
if (status.condition_home_position_valid) {
if (TRANSITION_DENIED != arm_disarm(true, mavlink_fd_local, "command line")) {
2015-12-20 20:29:22 +01:00
vehicle_command_s cmd = {};
cmd.target_system = status.system_id;
cmd.target_component = status.component_id;
cmd.command = vehicle_command_s::VEHICLE_CMD_NAV_TAKEOFF;
// cmd.param1 = 0.25f; /* minimum pitch */
// /* param 2-3 unused */
// cmd.param4 = home_position.yaw;
// cmd.param5 = home_position.lat;
// cmd.param6 = home_position.lon;
// cmd.param7 = home_position.alt;
// XXX inspect use of publication handle
(void)orb_advertise(ORB_ID(vehicle_command), &cmd);
} else {
2015-12-20 20:29:22 +01:00
warnx("arming failed");
}
} else {
2015-12-20 20:29:22 +01:00
warnx("rejecting takeoff, no position lock yet. Please retry..");
}
2015-12-20 20:29:22 +01:00
px4_close(mavlink_fd_local);
return 0;
}
if (!strcmp(argv[1], "land")) {
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
vehicle_command_s cmd = {};
cmd.target_system = status.system_id;
cmd.target_component = status.component_id;
cmd.command = vehicle_command_s::VEHICLE_CMD_NAV_LAND;
// cmd.param1 = 0.25f; /* minimum pitch */
// /* param 2-3 unused */
// cmd.param4 = home_position.yaw;
// cmd.param5 = home_position.lat;
// cmd.param6 = home_position.lon;
// cmd.param7 = home_position.alt;
// XXX inspect use of publication handle
(void)orb_advertise(ORB_ID(vehicle_command), &cmd);
px4_close(mavlink_fd_local);
return 0;
}
2013-07-16 09:35:31 +02:00
usage("unrecognized command");
return 1;
2013-07-16 09:35:31 +02:00
}
void usage(const char *reason)
{
2015-11-03 22:53:03 +01:00
if (reason && *reason > 0) {
PX4_INFO("%s", reason);
2014-05-11 13:36:51 +02:00
}
2013-07-16 09:35:31 +02:00
2015-11-03 22:53:03 +01:00
PX4_INFO("usage: commander {start|stop|status|calibrate|check|arm|disarm}\n");
2013-07-16 09:35:31 +02:00
}
2013-02-24 21:57:38 +01:00
2013-08-27 23:08:00 +02:00
void print_status()
{
warnx("type: %s", (status.is_rotary_wing) ? "symmetric motion" : "forward motion");
2015-09-27 18:57:51 +02:00
warnx("power: USB: %s, BRICK: %s", (status.usb_connected) ? "[OK]" : "[NO]",
(status.condition_power_input_valid) ? " [OK]" : "[NO]");
2014-07-30 19:54:40 +02:00
warnx("avionics rail: %6.2f V", (double)status.avionics_power_rail_voltage);
2015-12-28 15:13:09 +01:00
warnx("home: lat = %.7f, lon = %.7f, alt = %.2f, yaw: %.2f", _home.lat, _home.lon, (double)_home.alt, (double)_home.yaw);
2015-06-08 15:19:41 +02:00
warnx("home: x = %.7f, y = %.7f, z = %.2f ", (double)_home.x, (double)_home.y, (double)_home.z);
/* read all relevant states */
int state_sub = orb_subscribe(ORB_ID(vehicle_status));
struct vehicle_status_s state;
orb_copy(ORB_ID(vehicle_status), state_sub, &state);
2013-08-27 23:08:00 +02:00
const char *armed_str;
switch (state.arming_state) {
case vehicle_status_s::ARMING_STATE_INIT:
2013-08-27 23:08:00 +02:00
armed_str = "INIT";
break;
case vehicle_status_s::ARMING_STATE_STANDBY:
2013-08-27 23:08:00 +02:00
armed_str = "STANDBY";
break;
case vehicle_status_s::ARMING_STATE_ARMED:
2013-08-27 23:08:00 +02:00
armed_str = "ARMED";
break;
case vehicle_status_s::ARMING_STATE_ARMED_ERROR:
2013-08-27 23:08:00 +02:00
armed_str = "ARMED_ERROR";
break;
case vehicle_status_s::ARMING_STATE_STANDBY_ERROR:
2013-08-27 23:08:00 +02:00
armed_str = "STANDBY_ERROR";
break;
case vehicle_status_s::ARMING_STATE_REBOOT:
2013-08-27 23:08:00 +02:00
armed_str = "REBOOT";
break;
case vehicle_status_s::ARMING_STATE_IN_AIR_RESTORE:
2013-08-27 23:08:00 +02:00
armed_str = "IN_AIR_RESTORE";
break;
default:
armed_str = "ERR: UNKNOWN STATE";
break;
}
px4_close(state_sub);
2013-09-01 10:29:30 +02:00
warnx("arming: %s", armed_str);
}
2013-09-08 21:06:55 +02:00
static orb_advert_t status_pub;
transition_result_t arm_disarm(bool arm, const int mavlink_fd_local, const char *armedBy)
{
2014-05-11 13:36:51 +02:00
transition_result_t arming_res = TRANSITION_NOT_CHANGED;
// For HIL platforms, require that simulated sensors are connected
if (arm && hrt_absolute_time() > commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL &&
is_hil_setup(autostart_id) && status.hil_state != vehicle_status_s::HIL_STATE_ON) {
mavlink_and_console_log_critical(mavlink_fd_local, "HIL platform: Connect to simulator before arming");
return TRANSITION_DENIED;
}
2014-05-11 13:36:51 +02:00
// Transition the armed state. By passing mavlink_fd to arming_state_transition it will
// output appropriate error messages if the state cannot transition.
arming_res = arming_state_transition(&status, &safety, arm ? vehicle_status_s::ARMING_STATE_ARMED : vehicle_status_s::ARMING_STATE_STANDBY, &armed,
true /* fRunPreArmChecks */, mavlink_fd_local);
2014-05-11 13:36:51 +02:00
if (arming_res == TRANSITION_CHANGED && mavlink_fd) {
mavlink_log_info(mavlink_fd_local, "[cmd] %s by %s", arm ? "ARMED" : "DISARMED", armedBy);
2014-05-11 13:36:51 +02:00
} else if (arming_res == TRANSITION_DENIED) {
tune_negative(true);
}
return arming_res;
}
bool handle_command(struct vehicle_status_s *status_local, const struct safety_s *safety_local,
struct vehicle_command_s *cmd, struct actuator_armed_s *armed_local,
struct home_position_s *home, struct vehicle_global_position_s *global_pos,
2015-12-12 13:01:49 +01:00
struct vehicle_local_position_s *local_pos, struct vehicle_attitude_s *attitude, orb_advert_t *home_pub,
orb_advert_t *command_ack_pub, struct vehicle_command_ack_s *command_ack)
{
/* only handle commands that are meant to be handled by this system and component */
if (cmd->target_system != status_local->system_id || ((cmd->target_component != status_local->component_id)
&& (cmd->target_component != 0))) { // component_id 0: valid for all components
return false;
}
/* result of the command */
2015-05-26 22:55:14 -07:00
unsigned cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_UNSUPPORTED;
/* request to set different system mode */
switch (cmd->command) {
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_DO_SET_MODE: {
uint8_t base_mode = (uint8_t)cmd->param1;
uint8_t custom_main_mode = (uint8_t)cmd->param2;
uint8_t custom_sub_mode = (uint8_t)cmd->param3;
transition_result_t arming_ret = TRANSITION_NOT_CHANGED;
transition_result_t main_ret = TRANSITION_NOT_CHANGED;
/* set HIL state */
hil_state_t new_hil_state = (base_mode & MAV_MODE_FLAG_HIL_ENABLED) ? vehicle_status_s::HIL_STATE_ON : vehicle_status_s::HIL_STATE_OFF;
transition_result_t hil_ret = hil_state_transition(new_hil_state, status_pub, status_local, mavlink_fd);
2013-09-08 21:06:55 +02:00
// Transition the arming state
bool cmd_arm = base_mode & MAV_MODE_FLAG_SAFETY_ARMED;
arming_ret = arm_disarm(cmd_arm, mavlink_fd, "set mode command");
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
if (cmd_arm && (arming_ret == TRANSITION_CHANGED) &&
(hrt_absolute_time() > (commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL))) {
commander_set_home_position(*home_pub, *home, *local_pos, *global_pos, *attitude);
}
if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
/* use autopilot-specific mode */
if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_MANUAL) {
/* MANUAL */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_MANUAL);
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_ALTCTL) {
/* ALTCTL */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_ALTCTL);
2012-12-27 17:13:48 +01:00
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_POSCTL) {
/* POSCTL */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_POSCTL);
2012-12-27 17:13:48 +01:00
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_AUTO) {
/* AUTO */
if (custom_sub_mode > 0) {
switch(custom_sub_mode) {
case PX4_CUSTOM_SUB_MODE_AUTO_LOITER:
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_LOITER);
break;
case PX4_CUSTOM_SUB_MODE_AUTO_MISSION:
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_MISSION);
break;
case PX4_CUSTOM_SUB_MODE_AUTO_RTL:
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_RTL);
break;
2015-12-02 12:04:34 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF:
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_TAKEOFF);
break;
2015-12-18 09:48:47 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_LAND:
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_LAND);
break;
default:
main_ret = TRANSITION_DENIED;
mavlink_log_critical(mavlink_fd, "Unsupported auto mode");
break;
}
} else {
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_MISSION);
}
2014-05-20 00:03:00 +02:00
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_ACRO) {
/* ACRO */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_ACRO);
2014-05-21 10:40:58 +02:00
2015-05-17 12:58:44 +02:00
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_STABILIZED) {
/* STABILIZED */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_STAB);
2014-01-29 21:21:16 +01:00
} else if (custom_main_mode == PX4_CUSTOM_MAIN_MODE_OFFBOARD) {
/* OFFBOARD */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_OFFBOARD);
}
2012-12-27 17:13:48 +01:00
} else {
/* use base mode */
if (base_mode & MAV_MODE_FLAG_AUTO_ENABLED) {
/* AUTO */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_AUTO_MISSION);
} else if (base_mode & MAV_MODE_FLAG_MANUAL_INPUT_ENABLED) {
if (base_mode & MAV_MODE_FLAG_GUIDED_ENABLED) {
/* POSCTL */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_POSCTL);
} else if (base_mode & MAV_MODE_FLAG_STABILIZE_ENABLED) {
2015-05-17 12:58:44 +02:00
/* STABILIZED */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_STAB);
} else {
/* MANUAL */
main_ret = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_MANUAL);
}
}
}
if (hil_ret != TRANSITION_DENIED && arming_ret != TRANSITION_DENIED && main_ret != TRANSITION_DENIED) {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;
if (arming_ret == TRANSITION_DENIED) {
mavlink_log_critical(mavlink_fd, "Rejecting arming cmd");
}
if (main_ret == TRANSITION_DENIED) {
mavlink_log_critical(mavlink_fd, "Rejecting mode switch cmd");
}
}
}
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_COMPONENT_ARM_DISARM: {
2015-03-08 14:49:55 +01:00
// Adhere to MAVLink specs, but base on knowledge that these fundamentally encode ints
// for logic state parameters
if (static_cast<int>(cmd->param1 + 0.5f) != 0 && static_cast<int>(cmd->param1 + 0.5f) != 1) {
mavlink_log_critical(mavlink_fd, "Unsupported ARM_DISARM param: %.3f", (double)cmd->param1);
2014-05-11 13:36:51 +02:00
} else {
bool cmd_arms = (static_cast<int>(cmd->param1 + 0.5f) == 1);
2014-05-11 13:36:51 +02:00
// Flick to inair restore first if this comes from an onboard system
if (cmd->source_system == status_local->system_id && cmd->source_component == status_local->component_id) {
status_local->arming_state = vehicle_status_s::ARMING_STATE_IN_AIR_RESTORE;
2014-05-11 13:36:51 +02:00
}
else {
// Refuse to arm if preflight checks have failed
if ((!status.hil_state) != vehicle_status_s::HIL_STATE_ON && !status.condition_system_sensors_initialized) {
mavlink_log_critical(mavlink_fd, "Arming DENIED. Preflight checks have failed.");
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_DENIED;
break;
}
}
2014-05-11 13:36:51 +02:00
transition_result_t arming_res = arm_disarm(cmd_arms, mavlink_fd, "arm/disarm component command");
2014-05-11 13:36:51 +02:00
if (arming_res == TRANSITION_DENIED) {
mavlink_log_critical(mavlink_fd, "REJECTING component arm cmd");
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;
2014-05-11 13:36:51 +02:00
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
2015-12-20 20:29:22 +01:00
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
if (cmd_arms && (arming_res == TRANSITION_CHANGED) &&
(hrt_absolute_time() > (commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL))) {
commander_set_home_position(*home_pub, *home, *local_pos, *global_pos, *attitude);
}
2014-05-11 13:36:51 +02:00
}
}
2013-09-22 14:43:12 +02:00
}
break;
2013-01-11 07:42:09 +01:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_OVERRIDE_GOTO: {
// TODO listen vehicle_command topic directly from navigator (?)
// Increase by 0.5f and rely on the integer cast
// implicit floor(). This is the *safest* way to
// convert from floats representing small ints to actual ints.
unsigned int mav_goto = (cmd->param1 + 0.5f);
if (mav_goto == 0) { // MAV_GOTO_DO_HOLD
status_local->nav_state = vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER;
mavlink_log_critical(mavlink_fd, "Pause mission cmd");
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else if (mav_goto == 1) { // MAV_GOTO_DO_CONTINUE
status_local->nav_state = vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION;
mavlink_log_critical(mavlink_fd, "Continue mission cmd");
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else {
mavlink_log_critical(mavlink_fd, "REJ CMD: %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f",
(double)cmd->param1,
(double)cmd->param2,
(double)cmd->param3,
(double)cmd->param4,
(double)cmd->param5,
(double)cmd->param6,
(double)cmd->param7);
}
}
break;
2015-01-16 16:46:16 +01:00
/* Flight termination */
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_DO_FLIGHTTERMINATION: {
2014-07-19 14:39:41 +02:00
if (cmd->param1 > 0.5f) {
//XXX update state machine?
armed_local->force_failsafe = true;
2014-08-15 00:07:38 +02:00
warnx("forcing failsafe (termination)");
} else {
2014-07-19 14:39:41 +02:00
armed_local->force_failsafe = false;
2014-08-15 00:07:38 +02:00
warnx("disabling failsafe (termination)");
}
2014-08-14 22:38:48 +02:00
/* param2 is currently used for other failsafe modes */
status_local->engine_failure_cmd = false;
status_local->data_link_lost_cmd = false;
status_local->gps_failure_cmd = false;
status_local->rc_signal_lost_cmd = false;
2014-08-14 22:38:48 +02:00
if ((int)cmd->param2 <= 0) {
/* reset all commanded failure modes */
warnx("reset all non-flighttermination failsafe commands");
2014-08-14 22:38:48 +02:00
} else if ((int)cmd->param2 == 1) {
/* trigger engine failure mode */
status_local->engine_failure_cmd = true;
warnx("engine failure mode commanded");
2014-08-14 22:38:48 +02:00
} else if ((int)cmd->param2 == 2) {
/* trigger data link loss mode */
status_local->data_link_lost_cmd = true;
warnx("data link loss mode commanded");
2014-08-14 22:38:48 +02:00
} else if ((int)cmd->param2 == 3) {
/* trigger gps loss mode */
status_local->gps_failure_cmd = true;
warnx("gps loss mode commanded");
2014-08-14 22:38:48 +02:00
} else if ((int)cmd->param2 == 4) {
/* trigger rc loss mode */
status_local->rc_signal_lost_cmd = true;
warnx("rc loss mode commanded");
}
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
}
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_DO_SET_HOME: {
bool use_current = cmd->param1 > 0.5f;
2014-05-11 13:36:51 +02:00
if (use_current) {
/* use current position */
if (status_local->condition_global_position_valid) {
home->lat = global_pos->lat;
home->lon = global_pos->lon;
home->alt = global_pos->alt;
home->timestamp = hrt_absolute_time();
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;
}
} else {
/* use specified position */
home->lat = cmd->param5;
home->lon = cmd->param6;
home->alt = cmd->param7;
home->timestamp = hrt_absolute_time();
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
}
2015-05-26 22:55:14 -07:00
if (cmd_result == vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED) {
2015-10-25 14:53:41 +01:00
mavlink_and_console_log_info(mavlink_fd, "Home position: %.7f, %.7f, %.2f", home->lat, home->lon, (double)home->alt);
/* announce new home position */
if (*home_pub != nullptr) {
2014-04-05 16:59:01 +04:00
orb_publish(ORB_ID(home_position), *home_pub, home);
} else {
2014-04-05 16:59:01 +04:00
*home_pub = orb_advertise(ORB_ID(home_position), home);
}
/* mark home position as set */
status_local->condition_home_position_valid = true;
}
}
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_NAV_GUIDED_ENABLE: {
transition_result_t res = TRANSITION_DENIED;
2015-05-26 22:55:14 -07:00
static main_state_t main_state_pre_offboard = vehicle_status_s::MAIN_STATE_MANUAL;
2015-05-26 22:55:14 -07:00
if (status_local->main_state != vehicle_status_s::MAIN_STATE_OFFBOARD) {
main_state_pre_offboard = status_local->main_state;
}
if (cmd->param1 > 0.5f) {
2015-05-26 22:55:14 -07:00
res = main_state_transition(status_local, vehicle_status_s::MAIN_STATE_OFFBOARD);
if (res == TRANSITION_DENIED) {
print_reject_mode(status_local, "OFFBOARD");
status_local->offboard_control_set_by_command = false;
} else {
/* Set flag that offboard was set via command, main state is not overridden by rc */
status_local->offboard_control_set_by_command = true;
}
} else {
/* If the mavlink command is used to enable or disable offboard control:
* switch back to previous mode when disabling */
res = main_state_transition(status_local, main_state_pre_offboard);
status_local->offboard_control_set_by_command = false;
}
}
break;
case vehicle_command_s::VEHICLE_CMD_NAV_TAKEOFF: {
/* ok, home set, use it to take off */
if (TRANSITION_CHANGED == main_state_transition(&status, vehicle_status_s::MAIN_STATE_AUTO_TAKEOFF)) {
warnx("taking off!");
} else {
warnx("takeoff denied");
}
}
break;
case vehicle_command_s::VEHICLE_CMD_NAV_LAND: {
/* ok, home set, use it to take off */
if (TRANSITION_CHANGED == main_state_transition(&status, vehicle_status_s::MAIN_STATE_AUTO_LAND)) {
warnx("landing!");
} else {
warnx("landing denied");
}
}
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_CALIBRATION:
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_SET_SENSOR_OFFSETS:
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_STORAGE:
2015-08-23 13:50:59 +02:00
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_UAVCAN:
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_CUSTOM_0:
case vehicle_command_s::VEHICLE_CMD_CUSTOM_1:
case vehicle_command_s::VEHICLE_CMD_CUSTOM_2:
case vehicle_command_s::VEHICLE_CMD_PAYLOAD_PREPARE_DEPLOY:
case vehicle_command_s::VEHICLE_CMD_PAYLOAD_CONTROL_DEPLOY:
case vehicle_command_s::VEHICLE_CMD_DO_MOUNT_CONTROL:
case vehicle_command_s::VEHICLE_CMD_DO_MOUNT_CONTROL_QUAT:
case vehicle_command_s::VEHICLE_CMD_DO_MOUNT_CONFIGURE:
case vehicle_command_s::VEHICLE_CMD_DO_TRIGGER_CONTROL:
case vehicle_command_s::VEHICLE_CMD_DO_VTOL_TRANSITION:
/* ignore commands that handled in low prio loop */
break;
default:
/* Warn about unsupported commands, this makes sense because only commands
* to this component ID (or all) are passed by mavlink. */
2015-12-12 13:01:49 +01:00
answer_command(*cmd, vehicle_command_s::VEHICLE_CMD_RESULT_UNSUPPORTED, *command_ack_pub, *command_ack);
break;
}
2014-05-11 13:36:51 +02:00
2015-05-26 22:55:14 -07:00
if (cmd_result != vehicle_command_s::VEHICLE_CMD_RESULT_UNSUPPORTED) {
/* already warned about unsupported commands in "default" case */
2015-12-12 13:01:49 +01:00
answer_command(*cmd, cmd_result, *command_ack_pub, *command_ack);
}
2014-06-29 13:55:55 -07:00
return true;
}
/**
* @brief This function initializes the home position of the vehicle. This happens first time we get a good GPS fix and each
* time the vehicle is armed with a good GPS fix.
**/
2015-01-16 16:46:16 +01:00
static void commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
const vehicle_local_position_s &localPosition, const vehicle_global_position_s &globalPosition,
const vehicle_attitude_s &attitude)
{
//Need global position fix to be able to set home
2015-01-16 16:46:16 +01:00
if (!status.condition_global_position_valid) {
return;
}
//Ensure that the GPS accuracy is good enough for intializing home
2015-01-16 16:46:16 +01:00
if (globalPosition.eph > eph_threshold || globalPosition.epv > epv_threshold) {
return;
}
//Set home position
home.timestamp = hrt_absolute_time();
home.lat = globalPosition.lat;
home.lon = globalPosition.lon;
home.alt = globalPosition.alt;
home.x = localPosition.x;
home.y = localPosition.y;
home.z = localPosition.z;
home.yaw = attitude.yaw;
PX4_INFO("home: %.7f, %.7f, %.2f", home.lat, home.lon, (double)home.alt);
/* announce new home position */
if (homePub != nullptr) {
orb_publish(ORB_ID(home_position), homePub, &home);
} else {
homePub = orb_advertise(ORB_ID(home_position), &home);
}
//Play tune first time we initialize HOME
2015-01-16 16:46:16 +01:00
if (!status.condition_home_position_valid) {
2015-06-13 18:37:19 +02:00
tune_home_set(true);
}
/* mark home position as set */
status.condition_home_position_valid = true;
}
int commander_thread_main(int argc, char *argv[])
{
/* not yet initialized */
commander_initialized = false;
bool sensor_fail_tune_played = false;
bool arm_tune_played = false;
2015-10-24 19:14:23 +02:00
bool was_landed = true;
2014-04-02 11:57:41 +04:00
bool was_armed = false;
Fixes for qurt HIL build Workaround required Eigen downgrade to 3.2. Hexagon toolchain does not support C++11 features of newest version of Eigen. Running make qurt_fixup will downgrade and patch Eigen for qurt. Running make restore will revert the patch and do a git submodule update to restore the expected Eigen version. Added a "restore" target to undo qurt_fixup Before doing a qurt build run: make qurt_fixup That will downgrade Eigen to 3.2 and apply the require patch. To build another target after downgrading: make restore Them make the desired target (other than qurt). Fixed type used in orb_priority to be consistent with the code (int* was used in declaration but int32_t* used in code) Removed unused class member variable in sensors.cpp Added cmake fix for unit tests. The location of px4_log.c changed. Fixed the qurt drv_hrt.c implementation to use us instead of ms for time resolution Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Changed PX4_DEBUG to PX4_WARN when checking for the error condition for store_poll_waiter in vdev.cpp Updated the px4_log.h file to make calls to the qurt_log functions. The qurt_log function is defined in the platforms/qurt layer. Added an option to control starting the commander module in HIL mode. Moved the flight specific drivers to the configuration file instead of adding them to the common tool chain file because HIL mode does not need them. Added the uorb Subscriber and Publisher classes Call PX4_ISFINITE macro instead of isfinite(). Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Signed-off-by: Mark Charlebois <charlebm@gmail.com>
2015-08-25 21:59:01 -07:00
bool startup_in_hil = false;
2015-08-26 16:17:07 +02:00
#ifdef __PX4_NUTTX
/* NuttX indicates 3 arguments when only 2 are present */
argc -= 1;
#endif
if (argc > 2) {
if (!strcmp(argv[2],"-hil")) {
Fixes for qurt HIL build Workaround required Eigen downgrade to 3.2. Hexagon toolchain does not support C++11 features of newest version of Eigen. Running make qurt_fixup will downgrade and patch Eigen for qurt. Running make restore will revert the patch and do a git submodule update to restore the expected Eigen version. Added a "restore" target to undo qurt_fixup Before doing a qurt build run: make qurt_fixup That will downgrade Eigen to 3.2 and apply the require patch. To build another target after downgrading: make restore Them make the desired target (other than qurt). Fixed type used in orb_priority to be consistent with the code (int* was used in declaration but int32_t* used in code) Removed unused class member variable in sensors.cpp Added cmake fix for unit tests. The location of px4_log.c changed. Fixed the qurt drv_hrt.c implementation to use us instead of ms for time resolution Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Changed PX4_DEBUG to PX4_WARN when checking for the error condition for store_poll_waiter in vdev.cpp Updated the px4_log.h file to make calls to the qurt_log functions. The qurt_log function is defined in the platforms/qurt layer. Added an option to control starting the commander module in HIL mode. Moved the flight specific drivers to the configuration file instead of adding them to the common tool chain file because HIL mode does not need them. Added the uorb Subscriber and Publisher classes Call PX4_ISFINITE macro instead of isfinite(). Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Signed-off-by: Mark Charlebois <charlebm@gmail.com>
2015-08-25 21:59:01 -07:00
startup_in_hil = true;
} else {
2015-08-26 16:17:07 +02:00
PX4_ERR("Argument %s not supported.", argv[2]);
Fixes for qurt HIL build Workaround required Eigen downgrade to 3.2. Hexagon toolchain does not support C++11 features of newest version of Eigen. Running make qurt_fixup will downgrade and patch Eigen for qurt. Running make restore will revert the patch and do a git submodule update to restore the expected Eigen version. Added a "restore" target to undo qurt_fixup Before doing a qurt build run: make qurt_fixup That will downgrade Eigen to 3.2 and apply the require patch. To build another target after downgrading: make restore Them make the desired target (other than qurt). Fixed type used in orb_priority to be consistent with the code (int* was used in declaration but int32_t* used in code) Removed unused class member variable in sensors.cpp Added cmake fix for unit tests. The location of px4_log.c changed. Fixed the qurt drv_hrt.c implementation to use us instead of ms for time resolution Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Changed PX4_DEBUG to PX4_WARN when checking for the error condition for store_poll_waiter in vdev.cpp Updated the px4_log.h file to make calls to the qurt_log functions. The qurt_log function is defined in the platforms/qurt layer. Added an option to control starting the commander module in HIL mode. Moved the flight specific drivers to the configuration file instead of adding them to the common tool chain file because HIL mode does not need them. Added the uorb Subscriber and Publisher classes Call PX4_ISFINITE macro instead of isfinite(). Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Signed-off-by: Mark Charlebois <charlebm@gmail.com>
2015-08-25 21:59:01 -07:00
PX4_ERR("COMMANDER NOT STARTED");
thread_should_exit = true;
}
}
/* set parameters */
param_t _param_sys_type = param_find("MAV_TYPE");
param_t _param_system_id = param_find("MAV_SYS_ID");
param_t _param_component_id = param_find("MAV_COMP_ID");
2014-06-18 19:01:41 +02:00
param_t _param_enable_datalink_loss = param_find("COM_DL_LOSS_EN");
2014-07-20 17:53:04 +02:00
param_t _param_datalink_loss_timeout = param_find("COM_DL_LOSS_T");
2014-09-05 12:06:05 +02:00
param_t _param_rc_loss_timeout = param_find("COM_RC_LOSS_T");
param_t _param_datalink_regain_timeout = param_find("COM_DL_REG_T");
2014-09-05 08:59:00 +02:00
param_t _param_ef_throttle_thres = param_find("COM_EF_THROT");
param_t _param_ef_current2throttle_thres = param_find("COM_EF_C2T");
param_t _param_ef_time_thres = param_find("COM_EF_TIME");
param_t _param_autostart_id = param_find("SYS_AUTOSTART");
param_t _param_autosave_params = param_find("COM_AUTOS_PAR");
param_t _param_rc_in_off = param_find("COM_RC_IN_MODE");
param_t _param_eph = param_find("COM_HOME_H_T");
param_t _param_epv = param_find("COM_HOME_V_T");
2015-09-27 19:49:01 -04:00
param_t _param_geofence_action = param_find("GF_ACTION");
param_t _param_disarm_land = param_find("COM_DISARM_LAND");
param_t _param_map_mode_sw = param_find("RC_MAP_MODE_SW");
2015-11-22 12:43:58 +01:00
// These are too verbose, but we will retain them a little longer
// until we are sure we really don't need them.
// const char *main_states_str[vehicle_status_s::MAIN_STATE_MAX];
// main_states_str[vehicle_status_s::MAIN_STATE_MANUAL] = "MANUAL";
// main_states_str[vehicle_status_s::MAIN_STATE_ALTCTL] = "ALTCTL";
// main_states_str[vehicle_status_s::MAIN_STATE_POSCTL] = "POSCTL";
// main_states_str[vehicle_status_s::MAIN_STATE_AUTO_MISSION] = "AUTO_MISSION";
// main_states_str[vehicle_status_s::MAIN_STATE_AUTO_LOITER] = "AUTO_LOITER";
// main_states_str[vehicle_status_s::MAIN_STATE_AUTO_RTL] = "AUTO_RTL";
// main_states_str[vehicle_status_s::MAIN_STATE_ACRO] = "ACRO";
// main_states_str[vehicle_status_s::MAIN_STATE_STAB] = "STAB";
// main_states_str[vehicle_status_s::MAIN_STATE_OFFBOARD] = "OFFBOARD";
2015-11-22 12:43:58 +01:00
// const char *arming_states_str[vehicle_status_s::ARMING_STATE_MAX];
// arming_states_str[vehicle_status_s::ARMING_STATE_INIT] = "INIT";
// arming_states_str[vehicle_status_s::ARMING_STATE_STANDBY] = "STANDBY";
// arming_states_str[vehicle_status_s::ARMING_STATE_ARMED] = "ARMED";
// arming_states_str[vehicle_status_s::ARMING_STATE_ARMED_ERROR] = "ARMED_ERROR";
// arming_states_str[vehicle_status_s::ARMING_STATE_STANDBY_ERROR] = "STANDBY_ERROR";
// arming_states_str[vehicle_status_s::ARMING_STATE_REBOOT] = "REBOOT";
// arming_states_str[vehicle_status_s::ARMING_STATE_IN_AIR_RESTORE] = "IN_AIR_RESTORE";
// const char *nav_states_str[vehicle_status_s::NAVIGATION_STATE_MAX];
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_MANUAL] = "MANUAL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_STAB] = "STAB";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_RATTITUDE] = "RATTITUDE";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_ALTCTL] = "ALTCTL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_POSCTL] = "POSCTL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION] = "AUTO_MISSION";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER] = "AUTO_LOITER";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_RTL] = "AUTO_RTL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF] = "AUTO_TAKEOFF";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_RCRECOVER] = "AUTO_RCRECOVER";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_RTGS] = "AUTO_RTGS";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_LANDENGFAIL] = "AUTO_LANDENGFAIL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_AUTO_LANDGPSFAIL] = "AUTO_LANDGPSFAIL";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_ACRO] = "ACRO";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_LAND] = "LAND";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_DESCEND] = "DESCEND";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_TERMINATION] = "TERMINATION";
// nav_states_str[vehicle_status_s::NAVIGATION_STATE_OFFBOARD] = "OFFBOARD";
/* pthread for slow low prio thread */
pthread_t commander_low_prio_thread;
/* initialize */
2015-03-28 13:54:05 -07:00
if (led_init() != OK) {
mavlink_and_console_log_critical(mavlink_fd, "ERROR: LED INIT FAIL");
}
if (buzzer_init() != OK) {
2015-03-28 13:54:05 -07:00
mavlink_and_console_log_critical(mavlink_fd, "ERROR: BUZZER INIT FAIL");
}
if (battery_init() != OK) {
mavlink_and_console_log_critical(mavlink_fd, "ERROR: BATTERY INIT FAIL");
}
2015-06-22 09:58:01 +02:00
mavlink_fd = px4_open(MAVLINK_LOG_DEVICE, 0);
/* vehicle status topic */
2013-07-28 23:12:16 +04:00
memset(&status, 0, sizeof(status));
status.condition_landed = true; // initialize to safe value
// We want to accept RC inputs as default
status.rc_input_blocked = false;
status.rc_input_mode = vehicle_status_s::RC_IN_MODE_DEFAULT;
status.main_state =vehicle_status_s::MAIN_STATE_MANUAL;
status.main_state_prev = vehicle_status_s::MAIN_STATE_MAX;
status.nav_state = vehicle_status_s::NAVIGATION_STATE_MANUAL;
status.arming_state = vehicle_status_s::ARMING_STATE_INIT;
Fixes for qurt HIL build Workaround required Eigen downgrade to 3.2. Hexagon toolchain does not support C++11 features of newest version of Eigen. Running make qurt_fixup will downgrade and patch Eigen for qurt. Running make restore will revert the patch and do a git submodule update to restore the expected Eigen version. Added a "restore" target to undo qurt_fixup Before doing a qurt build run: make qurt_fixup That will downgrade Eigen to 3.2 and apply the require patch. To build another target after downgrading: make restore Them make the desired target (other than qurt). Fixed type used in orb_priority to be consistent with the code (int* was used in declaration but int32_t* used in code) Removed unused class member variable in sensors.cpp Added cmake fix for unit tests. The location of px4_log.c changed. Fixed the qurt drv_hrt.c implementation to use us instead of ms for time resolution Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Changed PX4_DEBUG to PX4_WARN when checking for the error condition for store_poll_waiter in vdev.cpp Updated the px4_log.h file to make calls to the qurt_log functions. The qurt_log function is defined in the platforms/qurt layer. Added an option to control starting the commander module in HIL mode. Moved the flight specific drivers to the configuration file instead of adding them to the common tool chain file because HIL mode does not need them. Added the uorb Subscriber and Publisher classes Call PX4_ISFINITE macro instead of isfinite(). Added px4_led.c to nuttx platform layer Use the posix version of px4_led.c for nuttx so we don't end up with duplicate files. It was moved out of common because it is not used by qurt. Signed-off-by: Mark Charlebois <charlebm@gmail.com>
2015-08-25 21:59:01 -07:00
if(startup_in_hil) {
status.hil_state = vehicle_status_s::HIL_STATE_ON;
} else {
status.hil_state = vehicle_status_s::HIL_STATE_OFF;
}
status.failsafe = false;
/* neither manual nor offboard control commands have been received */
2013-07-28 23:12:16 +04:00
status.offboard_control_signal_found_once = false;
status.rc_signal_found_once = false;
/* mark all signals lost as long as they haven't been found */
2013-07-28 23:12:16 +04:00
status.rc_signal_lost = true;
status.offboard_control_signal_lost = true;
status.data_link_lost = true;
2013-01-08 21:19:23 +01:00
/* set battery warning flag */
status.battery_warning = vehicle_status_s::VEHICLE_BATTERY_WARNING_NONE;
2013-08-15 17:27:29 +02:00
status.condition_battery_voltage_valid = false;
2013-07-28 23:12:16 +04:00
// XXX for now just set sensors as initialized
2013-07-28 23:12:16 +04:00
status.condition_system_sensors_initialized = true;
status.condition_system_prearm_error_reported = false;
status.condition_system_hotplug_timeout = false;
2013-07-28 23:12:16 +04:00
status.counter++;
status.timestamp = hrt_absolute_time();
status.condition_power_input_valid = true;
status.avionics_power_rail_voltage = -1.0f;
status.usb_connected = false;
// CIRCUIT BREAKERS
status.circuit_breaker_engaged_power_check = false;
status.circuit_breaker_engaged_airspd_check = false;
status.circuit_breaker_engaged_enginefailure_check = false;
status.circuit_breaker_engaged_gpsfailure_check = false;
get_circuit_breaker_params();
/* publish initial state */
status_pub = orb_advertise(ORB_ID(vehicle_status), &status);
if (status_pub == nullptr) {
warnx("ERROR: orb_advertise for topic vehicle_status failed (uorb app running?).\n");
warnx("exiting.");
px4_task_exit(ERROR);
}
/* Initialize armed with all false */
memset(&armed, 0, sizeof(armed));
2015-10-24 19:14:23 +02:00
/* armed topic */
orb_advert_t armed_pub = orb_advertise(ORB_ID(actuator_armed), &armed);
/* vehicle control mode topic */
memset(&control_mode, 0, sizeof(control_mode));
orb_advert_t control_mode_pub = orb_advertise(ORB_ID(vehicle_control_mode), &control_mode);
/* home position */
orb_advert_t home_pub = nullptr;
2015-06-08 15:19:41 +02:00
memset(&_home, 0, sizeof(_home));
2015-12-12 13:01:49 +01:00
/* command ack */
orb_advert_t command_ack_pub = nullptr;
struct vehicle_command_ack_s command_ack;
memset(&command_ack, 0, sizeof(command_ack));
/* init mission state, do it here to allow navigator to use stored mission even if mavlink failed to start */
orb_advert_t mission_pub = nullptr;
mission_s mission;
if (dm_read(DM_KEY_MISSION_STATE, 0, &mission, sizeof(mission_s)) == sizeof(mission_s)) {
if (mission.dataman_id >= 0 && mission.dataman_id <= 1) {
if (mission.count > 0) {
mavlink_log_info(mavlink_fd, "[cmd] Mission #%d loaded, %u WPs, curr: %d",
mission.dataman_id, mission.count, mission.current_seq);
}
} else {
const char *missionfail = "reading mission state failed";
warnx("%s", missionfail);
mavlink_log_critical(mavlink_fd, missionfail);
/* initialize mission state in dataman */
mission.dataman_id = 0;
mission.count = 0;
mission.current_seq = 0;
dm_write(DM_KEY_MISSION_STATE, 0, DM_PERSIST_POWER_ON_RESET, &mission, sizeof(mission_s));
}
mission_pub = orb_advertise(ORB_ID(offboard_mission), &mission);
orb_publish(ORB_ID(offboard_mission), mission_pub, &mission);
}
int ret;
/* Start monitoring loop */
unsigned counter = 0;
unsigned stick_off_counter = 0;
unsigned stick_on_counter = 0;
2013-08-15 17:27:29 +02:00
bool low_battery_voltage_actions_done = false;
bool critical_battery_voltage_actions_done = false;
hrt_abstime last_idle_time = 0;
bool status_changed = true;
bool param_init_forced = true;
bool updated = false;
/* Subscribe to safety topic */
int safety_sub = orb_subscribe(ORB_ID(safety));
memset(&safety, 0, sizeof(safety));
safety.safety_switch_available = false;
safety.safety_off = false;
/* Subscribe to mission result topic */
int mission_result_sub = orb_subscribe(ORB_ID(mission_result));
struct mission_result_s mission_result;
memset(&mission_result, 0, sizeof(mission_result));
/* Subscribe to geofence result topic */
int geofence_result_sub = orb_subscribe(ORB_ID(geofence_result));
struct geofence_result_s geofence_result;
memset(&geofence_result, 0, sizeof(geofence_result));
/* Subscribe to manual control data */
int sp_man_sub = orb_subscribe(ORB_ID(manual_control_setpoint));
struct manual_control_setpoint_s sp_man;
memset(&sp_man, 0, sizeof(sp_man));
/* Subscribe to offboard control data */
int offboard_control_mode_sub = orb_subscribe(ORB_ID(offboard_control_mode));
memset(&offboard_control_mode, 0, sizeof(offboard_control_mode));
/* Subscribe to telemetry status topics */
2015-07-12 12:34:48 +02:00
int telemetry_subs[ORB_MULTI_MAX_INSTANCES];
uint64_t telemetry_last_heartbeat[ORB_MULTI_MAX_INSTANCES];
uint64_t telemetry_last_dl_loss[ORB_MULTI_MAX_INSTANCES];
bool telemetry_lost[ORB_MULTI_MAX_INSTANCES];
2015-07-12 12:34:48 +02:00
for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
telemetry_subs[i] = -1;
telemetry_last_heartbeat[i] = 0;
telemetry_last_dl_loss[i] = 0;
telemetry_lost[i] = true;
}
/* Subscribe to global position */
int global_position_sub = orb_subscribe(ORB_ID(vehicle_global_position));
struct vehicle_global_position_s global_position;
memset(&global_position, 0, sizeof(global_position));
/* Init EPH and EPV */
global_position.eph = 1000.0f;
global_position.epv = 1000.0f;
/* Subscribe to local position data */
int local_position_sub = orb_subscribe(ORB_ID(vehicle_local_position));
struct vehicle_local_position_s local_position = {};
/* Subscribe to attitude data */
int attitude_sub = orb_subscribe(ORB_ID(vehicle_attitude));
struct vehicle_attitude_s attitude = {};
/* Subscribe to land detector */
int land_detector_sub = orb_subscribe(ORB_ID(vehicle_land_detected));
struct vehicle_land_detected_s land_detector = {};
2013-07-28 23:12:16 +04:00
/*
* The home position is set based on GPS only, to prevent a dependency between
* position estimator and commander. RAW GPS is more than good enough for a
* non-flying vehicle.
*/
/* Subscribe to GPS topic */
int gps_sub = orb_subscribe(ORB_ID(vehicle_gps_position));
struct vehicle_gps_position_s gps_position;
memset(&gps_position, 0, sizeof(gps_position));
2014-07-01 09:51:35 +02:00
gps_position.eph = FLT_MAX;
gps_position.epv = FLT_MAX;
/* Subscribe to sensor topic */
int sensor_sub = orb_subscribe(ORB_ID(sensor_combined));
struct sensor_combined_s sensors;
memset(&sensors, 0, sizeof(sensors));
/* Subscribe to differential pressure topic */
2013-04-19 18:28:06 +02:00
int diff_pres_sub = orb_subscribe(ORB_ID(differential_pressure));
struct differential_pressure_s diff_pres;
memset(&diff_pres, 0, sizeof(diff_pres));
2012-10-15 08:52:41 +02:00
/* Subscribe to command topic */
int cmd_sub = orb_subscribe(ORB_ID(vehicle_command));
struct vehicle_command_s cmd;
memset(&cmd, 0, sizeof(cmd));
/* Subscribe to parameters changed topic */
int param_changed_sub = orb_subscribe(ORB_ID(parameter_update));
/* Subscribe to battery topic */
int battery_sub = orb_subscribe(ORB_ID(battery_status));
struct battery_status_s battery;
memset(&battery, 0, sizeof(battery));
/* Subscribe to subsystem info topic */
int subsys_sub = orb_subscribe(ORB_ID(subsystem_info));
struct subsystem_info_s info;
memset(&info, 0, sizeof(info));
/* Subscribe to position setpoint triplet */
int pos_sp_triplet_sub = orb_subscribe(ORB_ID(position_setpoint_triplet));
struct position_setpoint_triplet_s pos_sp_triplet;
memset(&pos_sp_triplet, 0, sizeof(pos_sp_triplet));
/* Subscribe to system power */
int system_power_sub = orb_subscribe(ORB_ID(system_power));
struct system_power_s system_power;
memset(&system_power, 0, sizeof(system_power));
/* Subscribe to actuator controls (outputs) */
int actuator_controls_sub = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
struct actuator_controls_s actuator_controls;
memset(&actuator_controls, 0, sizeof(actuator_controls));
/* Subscribe to vtol vehicle status topic */
int vtol_vehicle_status_sub = orb_subscribe(ORB_ID(vtol_vehicle_status));
//struct vtol_vehicle_status_s vtol_status;
memset(&vtol_status, 0, sizeof(vtol_status));
vtol_status.vtol_in_rw_mode = true; //default for vtol is rotary wing
control_status_leds(&status, &armed, true);
/* now initialized */
commander_initialized = true;
thread_running = true;
/* update vehicle status to find out vehicle type (required for preflight checks) */
param_get(_param_sys_type, &(status.system_type)); // get system type
status.is_rotary_wing = is_rotary_wing(&status) || is_vtol(&status);
bool checkAirspeed = false;
/* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing */
if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) {
checkAirspeed = true;
}
// Run preflight check
2015-09-04 19:57:44 +02:00
int32_t rc_in_off = 0;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
param_get(_param_autostart_id, &autostart_id);
2015-10-06 11:48:35 +02:00
param_get(_param_rc_in_off, &rc_in_off);
status.rc_input_mode = rc_in_off;
2015-06-10 11:05:56 -06:00
if (is_hil_setup(autostart_id)) {
// HIL configuration selected: real sensors will be disabled
status.condition_system_sensors_initialized = false;
set_tune_override(TONE_STARTUP_TUNE); //normal boot tune
} else {
// sensor diagnostics done continiously, not just at boot so don't warn about any issues just yet
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true,
checkAirspeed, (status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), !status.circuit_breaker_engaged_gpsfailure_check, false);
set_tune_override(TONE_STARTUP_TUNE); //normal boot tune
}
commander_boot_timestamp = hrt_absolute_time();
transition_result_t arming_ret;
2014-06-18 19:01:41 +02:00
int32_t datalink_loss_enabled = false;
2014-07-20 17:53:04 +02:00
int32_t datalink_loss_timeout = 10;
2014-09-05 12:06:05 +02:00
float rc_loss_timeout = 0.5;
int32_t datalink_regain_timeout = 0;
2014-09-05 08:59:00 +02:00
2015-11-02 11:51:50 +01:00
int32_t geofence_action = 0;
2015-09-27 19:49:01 -04:00
2014-09-05 08:59:00 +02:00
/* Thresholds for engine failure detection */
int32_t ef_throttle_thres = 1.0f;
int32_t ef_current2throttle_thres = 0.0f;
int32_t ef_time_thres = 1000.0f;
uint64_t timestamp_engine_healthy = 0; /**< absolute time when engine was healty */
2014-06-18 19:01:41 +02:00
int autosave_params; /**< Autosave of parameters enabled/disabled, loaded from parameter */
int32_t disarm_when_landed = 0;
int32_t map_mode_sw = 0;
/* check which state machines for changes, clear "changed" flag */
bool arming_state_changed = false;
bool main_state_changed = false;
bool failsafe_old = false;
/* initialize low priority thread */
pthread_attr_t commander_low_prio_attr;
pthread_attr_init(&commander_low_prio_attr);
pthread_attr_setstacksize(&commander_low_prio_attr, 2880);
struct sched_param param;
(void)pthread_attr_getschedparam(&commander_low_prio_attr, &param);
/* low priority */
param.sched_priority = SCHED_PRIORITY_DEFAULT - 50;
(void)pthread_attr_setschedparam(&commander_low_prio_attr, &param);
pthread_create(&commander_low_prio_thread, &commander_low_prio_attr, commander_low_prio_loop, NULL);
pthread_attr_destroy(&commander_low_prio_attr);
while (!thread_should_exit) {
if (mavlink_fd < 0 && counter % (1000000 / MAVLINK_OPEN_INTERVAL) == 0) {
/* try to open the mavlink log device every once in a while */
2015-06-22 09:58:01 +02:00
mavlink_fd = px4_open(MAVLINK_LOG_DEVICE, 0);
}
arming_ret = TRANSITION_NOT_CHANGED;
/* update parameters */
orb_check(param_changed_sub, &updated);
if (updated || param_init_forced) {
param_init_forced = false;
2015-03-23 10:52:32 -07:00
/* parameters changed */
2015-03-23 10:52:32 -07:00
struct parameter_update_s param_changed;
orb_copy(ORB_ID(parameter_update), param_changed_sub, &param_changed);
/* update parameters */
if (!armed.armed) {
2013-07-28 23:12:16 +04:00
if (param_get(_param_sys_type, &(status.system_type)) != OK) {
warnx("failed getting new system type");
}
/* disable manual override for all systems that rely on electronic stabilization */
if (is_rotary_wing(&status) || (is_vtol(&status) && vtol_status.vtol_in_rw_mode)) {
2013-07-28 23:12:16 +04:00
status.is_rotary_wing = true;
} else {
2013-07-28 23:12:16 +04:00
status.is_rotary_wing = false;
}
/* set vehicle_status.is_vtol flag */
status.is_vtol = is_vtol(&status);
/* check and update system / component ID */
2013-07-28 23:12:16 +04:00
param_get(_param_system_id, &(status.system_id));
param_get(_param_component_id, &(status.component_id));
get_circuit_breaker_params();
status_changed = true;
// check if main mode switch has been assigned and if so run preflight checks in order
// to update status.condition_sensors_initialised
int32_t map_mode_sw_new;
param_get(_param_map_mode_sw, &map_mode_sw_new);
if (map_mode_sw == 0 && map_mode_sw != map_mode_sw_new && map_mode_sw_new < input_rc_s::RC_INPUT_MAX_CHANNELS && map_mode_sw_new > 0) {
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed,
(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
}
}
2014-05-11 13:36:51 +02:00
/* Safety parameters */
2014-06-18 19:01:41 +02:00
param_get(_param_enable_datalink_loss, &datalink_loss_enabled);
2014-07-20 17:53:04 +02:00
param_get(_param_datalink_loss_timeout, &datalink_loss_timeout);
2014-09-05 12:06:05 +02:00
param_get(_param_rc_loss_timeout, &rc_loss_timeout);
param_get(_param_rc_in_off, &rc_in_off);
status.rc_input_mode = rc_in_off;
param_get(_param_datalink_regain_timeout, &datalink_regain_timeout);
2014-09-05 08:59:00 +02:00
param_get(_param_ef_throttle_thres, &ef_throttle_thres);
param_get(_param_ef_current2throttle_thres, &ef_current2throttle_thres);
param_get(_param_ef_time_thres, &ef_time_thres);
2015-09-27 19:49:01 -04:00
param_get(_param_geofence_action, &geofence_action);
param_get(_param_disarm_land, &disarm_when_landed);
param_get(_param_map_mode_sw, &map_mode_sw);
/* Autostart id */
param_get(_param_autostart_id, &autostart_id);
/* Parameter autosave setting */
param_get(_param_autosave_params, &autosave_params);
/* EPH / EPV */
param_get(_param_eph, &eph_threshold);
param_get(_param_epv, &epv_threshold);
/* Set flag to autosave parameters if necessary */
if (updated && autosave_params != 0 && param_changed.saved == false) {
/* trigger an autosave */
need_param_autosave = true;
}
}
orb_check(sp_man_sub, &updated);
2013-01-11 07:42:09 +01:00
if (updated) {
orb_copy(ORB_ID(manual_control_setpoint), sp_man_sub, &sp_man);
}
orb_check(offboard_control_mode_sub, &updated);
2013-01-11 07:42:09 +01:00
if (updated) {
orb_copy(ORB_ID(offboard_control_mode), offboard_control_mode_sub, &offboard_control_mode);
}
2012-12-19 11:34:51 +01:00
if (offboard_control_mode.timestamp != 0 &&
offboard_control_mode.timestamp + OFFBOARD_TIMEOUT > hrt_absolute_time()) {
if (status.offboard_control_signal_lost) {
status.offboard_control_signal_lost = false;
status_changed = true;
}
} else {
if (!status.offboard_control_signal_lost) {
status.offboard_control_signal_lost = true;
status_changed = true;
}
}
2015-07-12 12:34:48 +02:00
for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
2015-07-12 12:34:48 +02:00
if (telemetry_subs[i] < 0 && (OK == orb_exists(ORB_ID(telemetry_status), i))) {
telemetry_subs[i] = orb_subscribe_multi(ORB_ID(telemetry_status), i);
}
orb_check(telemetry_subs[i], &updated);
if (updated) {
struct telemetry_status_s telemetry;
memset(&telemetry, 0, sizeof(telemetry));
2015-07-12 12:34:48 +02:00
orb_copy(ORB_ID(telemetry_status), telemetry_subs[i], &telemetry);
/* perform system checks when new telemetry link connected */
if (
/* we actually have a way to talk to the user */
mavlink_fd &&
/* we first connect a link or re-connect a link after loosing it */
(telemetry_last_heartbeat[i] == 0 || (hrt_elapsed_time(&telemetry_last_heartbeat[i]) > 3 * 1000 * 1000)) &&
/* and this link has a communication partner */
(telemetry.heartbeat_time > 0) &&
/* and it is still connected */
(hrt_elapsed_time(&telemetry.heartbeat_time) < 2 * 1000 * 1000) &&
/* and the system is not already armed (and potentially flying) */
!armed.armed) {
bool chAirspeed = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing
*/
if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) {
chAirspeed = true;
}
/* provide RC and sensor status feedback to the user */
2015-06-10 11:05:56 -06:00
if (is_hil_setup(autostart_id)) {
2015-06-06 07:56:48 -06:00
/* HIL configuration: check only RC input */
(void)Commander::preflightCheck(mavlink_fd, false, false, false, false, false,
(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), false, true);
} else {
/* check sensors also */
(void)Commander::preflightCheck(mavlink_fd, true, true, true, true, chAirspeed,
(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
2015-06-06 07:56:48 -06:00
}
}
2015-11-04 18:23:19 +01:00
/* set (and don't reset) telemetry via USB as active once a MAVLink connection is up */
if (telemetry.type == telemetry_status_s::TELEMETRY_STATUS_RADIO_TYPE_USB) {
_usb_telemetry_active = true;
}
if (telemetry.heartbeat_time > 0) {
telemetry_last_heartbeat[i] = telemetry.heartbeat_time;
}
}
}
orb_check(sensor_sub, &updated);
2013-01-11 07:42:09 +01:00
if (updated) {
2012-12-19 11:34:51 +01:00
orb_copy(ORB_ID(sensor_combined), sensor_sub, &sensors);
2014-08-24 13:44:43 +02:00
/* Check if the barometer is healthy and issue a warning in the GCS if not so.
* Because the barometer is used for calculating AMSL altitude which is used to ensure
* vertical separation from other airtraffic the operator has to know when the
* barometer is inoperational.
* */
if (hrt_elapsed_time(&sensors.baro_timestamp[0]) < FAILSAFE_DEFAULT_TIMEOUT) {
2014-08-24 13:44:43 +02:00
/* handle the case where baro was regained */
if (status.barometer_failure) {
status.barometer_failure = false;
status_changed = true;
mavlink_log_critical(mavlink_fd, "baro healthy");
}
2014-08-24 13:44:43 +02:00
} else {
if (!status.barometer_failure) {
status.barometer_failure = true;
status_changed = true;
mavlink_log_critical(mavlink_fd, "baro failed");
}
}
2012-12-19 11:34:51 +01:00
}
orb_check(diff_pres_sub, &updated);
if (updated) {
2013-04-19 18:28:06 +02:00
orb_copy(ORB_ID(differential_pressure), diff_pres_sub, &diff_pres);
}
orb_check(system_power_sub, &updated);
if (updated) {
orb_copy(ORB_ID(system_power), system_power_sub, &system_power);
if (hrt_elapsed_time(&system_power.timestamp) < 200000) {
if (system_power.servo_valid &&
!system_power.brick_valid &&
!system_power.usb_connected) {
/* flying only on servo rail, this is unsafe */
status.condition_power_input_valid = false;
} else {
status.condition_power_input_valid = true;
}
/* copy avionics voltage */
status.avionics_power_rail_voltage = system_power.voltage5V_v;
2015-11-04 18:23:19 +01:00
/* if the USB hardware connection went away, reboot */
if (status.usb_connected && !system_power.usb_connected) {
/*
* apparently the USB cable went away but we are still powered,
* so lets reset to a classic non-usb state.
*/
mavlink_log_critical(mavlink_fd, "USB disconnected, rebooting.")
usleep(400000);
px4_systemreset(false);
}
2015-11-04 18:23:19 +01:00
/* finally judge the USB connected state based on software detection */
status.usb_connected = _usb_telemetry_active;
}
}
check_valid(diff_pres.timestamp, DIFFPRESS_TIMEOUT, true, &(status.condition_airspeed_valid), &status_changed);
/* update safety topic */
orb_check(safety_sub, &updated);
if (updated) {
bool previous_safety_off = safety.safety_off;
orb_copy(ORB_ID(safety), safety_sub, &safety);
/* disarm if safety is now on and still armed */
if (status.hil_state == vehicle_status_s::HIL_STATE_OFF && safety.safety_switch_available && !safety.safety_off && armed.armed) {
arming_state_t new_arming_state = (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED ? vehicle_status_s::ARMING_STATE_STANDBY :
vehicle_status_s::ARMING_STATE_STANDBY_ERROR);
2014-05-11 13:36:51 +02:00
if (TRANSITION_CHANGED == arming_state_transition(&status, &safety, new_arming_state, &armed,
true /* fRunPreArmChecks */, mavlink_fd)) {
mavlink_log_info(mavlink_fd, "DISARMED by safety switch");
arming_state_changed = true;
}
}
//Notify the user if the status of the safety switch changes
2015-01-16 16:46:16 +01:00
if (safety.safety_switch_available && previous_safety_off != safety.safety_off) {
2015-01-16 16:46:16 +01:00
if (safety.safety_off) {
set_tune(TONE_NOTIFY_POSITIVE_TUNE);
2015-01-16 16:46:16 +01:00
} else {
tune_neutral(true);
}
status_changed = true;
}
}
/* update vtol vehicle status*/
orb_check(vtol_vehicle_status_sub, &updated);
if (updated) {
/* vtol status changed */
orb_copy(ORB_ID(vtol_vehicle_status), vtol_vehicle_status_sub, &vtol_status);
status.vtol_fw_permanent_stab = vtol_status.fw_permanent_stab;
2015-01-16 16:46:16 +01:00
/* Make sure that this is only adjusted if vehicle really is of type vtol */
if (is_vtol(&status)) {
status.is_rotary_wing = vtol_status.vtol_in_rw_mode;
status.in_transition_mode = vtol_status.vtol_in_trans_mode;
}
status_changed = true;
}
/* update global position estimate */
orb_check(global_position_sub, &updated);
2013-01-11 07:42:09 +01:00
if (updated) {
/* position changed */
vehicle_global_position_s gpos;
orb_copy(ORB_ID(vehicle_global_position), global_position_sub, &gpos);
/* copy to global struct if valid, with hysteresis */
// XXX consolidate this with local position handling and timeouts after release
// but we want a low-risk change now.
if (status.condition_global_position_valid) {
if (gpos.eph < eph_threshold * 2.5f) {
orb_copy(ORB_ID(vehicle_global_position), global_position_sub, &global_position);
}
} else {
if (gpos.eph < eph_threshold) {
orb_copy(ORB_ID(vehicle_global_position), global_position_sub, &global_position);
}
}
}
/* update local position estimate */
orb_check(local_position_sub, &updated);
2013-01-11 07:42:09 +01:00
if (updated) {
/* position changed */
orb_copy(ORB_ID(vehicle_local_position), local_position_sub, &local_position);
}
/* update attitude estimate */
orb_check(attitude_sub, &updated);
if (updated) {
/* position changed */
orb_copy(ORB_ID(vehicle_attitude), attitude_sub, &attitude);
}
//update condition_global_position_valid
//Global positions are only published by the estimators if they are valid
if (hrt_absolute_time() - global_position.timestamp > POSITION_TIMEOUT) {
//We have had no good fix for POSITION_TIMEOUT amount of time
if (status.condition_global_position_valid) {
set_tune_override(TONE_GPS_WARNING_TUNE);
status_changed = true;
2015-04-03 16:11:38 +02:00
status.condition_global_position_valid = false;
}
} else if (global_position.timestamp != 0) {
// Got good global position estimate
if (!status.condition_global_position_valid) {
status_changed = true;
2015-04-03 16:11:38 +02:00
status.condition_global_position_valid = true;
}
}
2014-05-11 13:36:51 +02:00
/* update condition_local_position_valid and condition_local_altitude_valid */
/* hysteresis for EPH */
bool local_eph_good;
if (status.condition_local_position_valid) {
if (local_position.eph > eph_threshold * 2.5f) {
local_eph_good = false;
} else {
local_eph_good = true;
}
} else {
if (local_position.eph < eph_threshold) {
local_eph_good = true;
} else {
local_eph_good = false;
}
}
check_valid(local_position.timestamp, POSITION_TIMEOUT, local_position.xy_valid
&& local_eph_good, &(status.condition_local_position_valid), &status_changed);
check_valid(local_position.timestamp, POSITION_TIMEOUT, local_position.z_valid,
&(status.condition_local_altitude_valid), &status_changed);
2013-08-27 23:08:00 +02:00
/* Update land detector */
static bool check_for_disarming = false;
orb_check(land_detector_sub, &updated);
if (updated) {
orb_copy(ORB_ID(vehicle_land_detected), land_detector_sub, &land_detector);
}
if ((updated && status.condition_local_altitude_valid) || check_for_disarming) {
if (status.condition_landed != land_detector.landed) {
status.condition_landed = land_detector.landed;
status_changed = true;
2013-08-27 23:08:00 +02:00
if (status.condition_landed) {
mavlink_and_console_log_info(mavlink_fd, "LANDING DETECTED");
2013-08-27 23:08:00 +02:00
} else {
mavlink_and_console_log_info(mavlink_fd, "TAKEOFF DETECTED");
}
}
if (disarm_when_landed > 0) {
if (land_detector.landed) {
if (!check_for_disarming && _inair_last_time > 0) {
_inair_last_time = land_detector.timestamp;
check_for_disarming = true;
}
if (_inair_last_time > 0 && ((hrt_absolute_time() - _inair_last_time) > (hrt_abstime)disarm_when_landed * 1000 * 1000)) {
mavlink_log_critical(mavlink_fd, "AUTO DISARMING AFTER LANDING");
arm_disarm(false, mavlink_fd, "auto disarm on land");
_inair_last_time = 0;
check_for_disarming = false;
}
} else {
_inair_last_time = land_detector.timestamp;
}
}
}
/* update battery status */
orb_check(battery_sub, &updated);
2013-07-28 23:12:16 +04:00
if (updated) {
orb_copy(ORB_ID(battery_status), battery_sub, &battery);
orb_copy(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_controls_sub, &actuator_controls);
/* only consider battery voltage if system has been running 2s and battery voltage is valid */
if (hrt_absolute_time() > commander_boot_timestamp + 2000000 && battery.voltage_filtered_v > 0.0f) {
status.battery_voltage = battery.voltage_filtered_v;
status.battery_current = battery.current_a;
status.battery_discharged_mah = battery.discharged_mah;
2013-08-15 17:27:29 +02:00
status.condition_battery_voltage_valid = true;
status.battery_cell_count = battery_get_n_cells();
/* get throttle (if armed), as we only care about energy negative throttle also counts */
float throttle = (armed.armed) ? fabsf(actuator_controls.control[3]) : 0.0f;
status.battery_remaining = battery_remaining_estimate_voltage(battery.voltage_filtered_v, battery.discharged_mah,
throttle);
2013-08-15 17:27:29 +02:00
}
}
/* update subsystem */
orb_check(subsys_sub, &updated);
2013-07-28 23:12:16 +04:00
if (updated) {
orb_copy(ORB_ID(subsystem_info), subsys_sub, &info);
2015-01-20 22:28:58 +01:00
//warnx("subsystem changed: %d\n", (int)info.subsystem_type);
/* mark / unmark as present */
if (info.present) {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_present |= info.subsystem_type;
} else {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_present &= ~info.subsystem_type;
}
/* mark / unmark as enabled */
if (info.enabled) {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_enabled |= info.subsystem_type;
} else {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_enabled &= ~info.subsystem_type;
}
/* mark / unmark as ok */
if (info.ok) {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_health |= info.subsystem_type;
} else {
2013-07-28 23:12:16 +04:00
status.onboard_control_sensors_health &= ~info.subsystem_type;
}
status_changed = true;
}
/* update position setpoint triplet */
orb_check(pos_sp_triplet_sub, &updated);
if (updated) {
orb_copy(ORB_ID(position_setpoint_triplet), pos_sp_triplet_sub, &pos_sp_triplet);
}
if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) {
/* compute system load */
uint64_t interval_runtime = system_load.tasks[0].total_runtime - last_idle_time;
2014-05-11 13:36:51 +02:00
if (last_idle_time > 0) {
status.load = 1.0f - ((float)interval_runtime / 1e6f); //system load is time spent in non-idle
}
last_idle_time = system_load.tasks[0].total_runtime;
}
/* if battery voltage is getting lower, warn using buzzer, etc. */
if (status.condition_battery_voltage_valid && status.battery_remaining < 0.18f && !low_battery_voltage_actions_done) {
low_battery_voltage_actions_done = true;
if (armed.armed) {
mavlink_log_critical(mavlink_fd, "LOW BATTERY, RETURN TO LAND ADVISED");
} else {
mavlink_log_critical(mavlink_fd, "LOW BATTERY, TAKEOFF DISCOURAGED");
}
status.battery_warning = vehicle_status_s::VEHICLE_BATTERY_WARNING_LOW;
status_changed = true;
} else if (!status.usb_connected && status.condition_battery_voltage_valid && status.battery_remaining < 0.09f
&& !critical_battery_voltage_actions_done && low_battery_voltage_actions_done) {
/* critical battery voltage, this is rather an emergency, change state machine */
critical_battery_voltage_actions_done = true;
status.battery_warning = vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL;
if (!armed.armed) {
arming_ret = arming_state_transition(&status, &safety,
vehicle_status_s::ARMING_STATE_STANDBY_ERROR,
&armed, true /* fRunPreArmChecks */, mavlink_fd);
if (arming_ret == TRANSITION_CHANGED) {
arming_state_changed = true;
mavlink_and_console_log_critical(mavlink_fd, "LOW BATTERY, LOCKING ARMING DOWN");
}
} else {
mavlink_and_console_log_emergency(mavlink_fd, "CRITICAL BATTERY, LAND IMMEDIATELY");
}
status_changed = true;
}
/* End battery voltage check */
2013-02-18 16:35:34 -08:00
/* If in INIT state, try to proceed to STANDBY state */
if (!status.calibration_enabled && status.arming_state == vehicle_status_s::ARMING_STATE_INIT) {
arming_ret = arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_STANDBY, &armed, true /* fRunPreArmChecks */,
mavlink_fd);
if (arming_ret == TRANSITION_CHANGED) {
arming_state_changed = true;
} else if (arming_ret == TRANSITION_DENIED) {
/* do not complain if not allowed into standby */
arming_ret = TRANSITION_NOT_CHANGED;
}
2013-07-28 23:12:16 +04:00
2013-02-18 16:35:34 -08:00
}
/*
* Check for valid position information.
*
* If the system has a valid position source from an onboard
* position estimator, it is safe to operate it autonomously.
* The flag_vector_flight_mode_ok flag indicates that a minimum
* set of position measurements is available.
*/
orb_check(gps_sub, &updated);
if (updated) {
orb_copy(ORB_ID(vehicle_gps_position), gps_sub, &gps_position);
}
/* Initialize map projection if gps is valid */
if (!map_projection_global_initialized()
&& (gps_position.eph < eph_threshold)
&& (gps_position.epv < epv_threshold)
&& hrt_elapsed_time((hrt_abstime *)&gps_position.timestamp_position) < 1e6) {
/* set reference for global coordinates <--> local coordiantes conversion and map_projection */
globallocalconverter_init((double)gps_position.lat * 1.0e-7, (double)gps_position.lon * 1.0e-7,
(float)gps_position.alt * 1.0e-3f, hrt_absolute_time());
}
/* check if GPS is ok */
if (!status.circuit_breaker_engaged_gpsfailure_check) {
bool gpsIsNoisy = gps_position.noise_per_ms > 0 && gps_position.noise_per_ms < COMMANDER_MAX_GPS_NOISE;
//Check if GPS receiver is too noisy while we are disarmed
if (!armed.armed && gpsIsNoisy) {
if (!status.gps_failure) {
mavlink_log_critical(mavlink_fd, "GPS signal noisy");
set_tune_override(TONE_GPS_WARNING_TUNE);
//GPS suffers from signal jamming or excessive noise, disable GPS-aided flight
status.gps_failure = true;
status_changed = true;
}
}
if (gps_position.fix_type >= 3 && hrt_elapsed_time(&gps_position.timestamp_position) < FAILSAFE_DEFAULT_TIMEOUT) {
/* handle the case where gps was regained */
if (status.gps_failure && !gpsIsNoisy) {
status.gps_failure = false;
status_changed = true;
2015-06-06 22:13:35 +02:00
mavlink_log_critical(mavlink_fd, "gps fix regained");
}
} else if (!status.gps_failure) {
status.gps_failure = true;
status_changed = true;
mavlink_log_critical(mavlink_fd, "gps fix lost");
}
}
2014-07-01 09:34:26 +02:00
/* start mission result check */
orb_check(mission_result_sub, &updated);
if (updated) {
orb_copy(ORB_ID(mission_result), mission_result_sub, &mission_result);
}
/* start geofence result check */
orb_check(geofence_result_sub, &updated);
if (updated) {
orb_copy(ORB_ID(geofence_result), geofence_result_sub, &geofence_result);
}
2015-09-27 19:49:01 -04:00
// Geofence actions
if (armed.armed && (geofence_result.geofence_action != geofence_result_s::GF_ACTION_NONE)) {
static bool geofence_loiter_on = false;
static bool geofence_rtl_on = false;
static uint8_t geofence_main_state_before_violation = vehicle_status_s::MAIN_STATE_MAX;
// check for geofence violation
if (geofence_result.geofence_violated) {
static hrt_abstime last_geofence_violation = 0;
const hrt_abstime geofence_violation_action_interval = 10000000; // 10 seconds
if (hrt_elapsed_time(&last_geofence_violation) > geofence_violation_action_interval) {
last_geofence_violation = hrt_absolute_time();
switch (geofence_result.geofence_action) {
case (geofence_result_s::GF_ACTION_NONE) : {
// do nothing
break;
}
case (geofence_result_s::GF_ACTION_WARN) : {
// do nothing, mavlink critical messages are sent by navigator
break;
}
case (geofence_result_s::GF_ACTION_LOITER) : {
if (TRANSITION_CHANGED == main_state_transition(&status, vehicle_status_s::MAIN_STATE_AUTO_LOITER)) {
geofence_loiter_on = true;
}
break;
}
case (geofence_result_s::GF_ACTION_RTL) : {
if (TRANSITION_CHANGED == main_state_transition(&status, vehicle_status_s::MAIN_STATE_AUTO_RTL)) {
geofence_rtl_on = true;
}
break;
}
case (geofence_result_s::GF_ACTION_TERMINATE) : {
warnx("Flight termination because of geofence");
mavlink_log_critical(mavlink_fd, "Geofence violation: flight termination");
armed.force_failsafe = true;
status_changed = true;
break;
}
}
}
}
// reset if no longer in LOITER or if manually switched to LOITER
geofence_loiter_on = geofence_loiter_on
&& (status.main_state == vehicle_status_s::MAIN_STATE_AUTO_LOITER)
&& (sp_man.loiter_switch == manual_control_setpoint_s::SWITCH_POS_OFF);
// reset if no longer in RTL or if manually switched to RTL
geofence_rtl_on = geofence_rtl_on
&& (status.main_state == vehicle_status_s::MAIN_STATE_AUTO_RTL)
&& (sp_man.return_switch == manual_control_setpoint_s::SWITCH_POS_OFF);
if (!geofence_loiter_on && !geofence_rtl_on) {
// store the last good main_state when not in a geofence triggered action (LOITER or RTL)
geofence_main_state_before_violation = status.main_state;
}
// revert geofence failsafe transition if sticks are moved and we were previously in MANUAL or ASSIST
if ((geofence_loiter_on || geofence_rtl_on) &&
(geofence_main_state_before_violation == vehicle_status_s::MAIN_STATE_MANUAL ||
geofence_main_state_before_violation == vehicle_status_s::MAIN_STATE_ALTCTL ||
geofence_main_state_before_violation == vehicle_status_s::MAIN_STATE_POSCTL ||
geofence_main_state_before_violation == vehicle_status_s::MAIN_STATE_ACRO ||
geofence_main_state_before_violation == vehicle_status_s::MAIN_STATE_STAB)) {
// transition to previous state if sticks are increased
const float min_stick_change = 0.2;
if ((_last_sp_man.timestamp != sp_man.timestamp) &&
((fabsf(sp_man.x) - fabsf(_last_sp_man.x) > min_stick_change) ||
(fabsf(sp_man.y) - fabsf(_last_sp_man.y) > min_stick_change) ||
(fabsf(sp_man.z) - fabsf(_last_sp_man.z) > min_stick_change) ||
(fabsf(sp_man.r) - fabsf(_last_sp_man.r) > min_stick_change))) {
main_state_transition(&status, geofence_main_state_before_violation);
}
}
}
/* Check for mission flight termination */
if (armed.armed && mission_result.flight_termination) {
armed.force_failsafe = true;
status_changed = true;
static bool flight_termination_printed = false;
if (!flight_termination_printed) {
2015-10-25 14:53:41 +01:00
mavlink_and_console_log_critical(mavlink_fd, "Geofence violation: flight termination");
flight_termination_printed = true;
}
if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) {
2015-10-25 14:53:41 +01:00
mavlink_and_console_log_critical(mavlink_fd, "Flight termination active");
}
2015-09-27 19:49:01 -04:00
}
2015-06-13 18:37:19 +02:00
/* Only evaluate mission state if home is set,
* this prevents false positives for the mission
* rejection. Back off 2 seconds to not overlay
* home tune.
*/
if (status.condition_home_position_valid &&
(hrt_elapsed_time(&_home.timestamp) > 2000000) &&
_last_mission_instance != mission_result.instance_count) {
if (!mission_result.valid) {
/* the mission is invalid */
tune_mission_fail(true);
warnx("mission fail");
} else if (mission_result.warning) {
/* the mission has a warning */
tune_mission_fail(true);
warnx("mission warning");
} else {
2015-06-13 18:37:19 +02:00
/* the mission is valid */
tune_mission_ok(true);
}
/* prevent further feedback until the mission changes */
_last_mission_instance = mission_result.instance_count;
}
/* RC input check */
if (!status.rc_input_blocked && sp_man.timestamp != 0 &&
(hrt_absolute_time() < sp_man.timestamp + (uint64_t)(rc_loss_timeout * 1e6f))) {
/* handle the case where RC signal was regained */
if (!status.rc_signal_found_once) {
status.rc_signal_found_once = true;
status_changed = true;
2013-02-20 10:38:06 -08:00
} else {
if (status.rc_signal_lost) {
mavlink_log_info(mavlink_fd, "MANUAL CONTROL REGAINED after %llums",
2015-01-16 16:46:16 +01:00
(hrt_absolute_time() - status.rc_signal_lost_timestamp) / 1000);
status_changed = true;
2013-02-20 10:38:06 -08:00
}
}
status.rc_signal_lost = false;
/* check if left stick is in lower left position and we are in MANUAL, Rattitude, or AUTO_READY mode or (ASSIST mode and landed) -> disarm
* do it only for rotary wings */
if (status.is_rotary_wing && status.rc_input_mode != vehicle_status_s::RC_IN_MODE_OFF &&
(status.arming_state == vehicle_status_s::ARMING_STATE_ARMED || status.arming_state == vehicle_status_s::ARMING_STATE_ARMED_ERROR) &&
2015-05-17 12:58:44 +02:00
(status.main_state == vehicle_status_s::MAIN_STATE_MANUAL ||
status.main_state == vehicle_status_s::MAIN_STATE_ACRO ||
status.main_state == vehicle_status_s::MAIN_STATE_STAB ||
status.main_state == vehicle_status_s::MAIN_STATE_RATTITUDE ||
2015-05-17 12:58:44 +02:00
status.condition_landed) &&
sp_man.r < -STICK_ON_OFF_LIMIT && sp_man.z < 0.1f) {
if (stick_off_counter > STICK_ON_OFF_COUNTER_LIMIT) {
/* disarm to STANDBY if ARMED or to STANDBY_ERROR if ARMED_ERROR */
arming_state_t new_arming_state = (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED ? vehicle_status_s::ARMING_STATE_STANDBY :
vehicle_status_s::ARMING_STATE_STANDBY_ERROR);
arming_ret = arming_state_transition(&status, &safety, new_arming_state, &armed, true /* fRunPreArmChecks */,
mavlink_fd);
if (arming_ret == TRANSITION_CHANGED) {
arming_state_changed = true;
}
stick_off_counter = 0;
2013-08-27 23:08:00 +02:00
} else {
stick_off_counter++;
}
} else {
stick_off_counter = 0;
}
/* check if left stick is in lower right position and we're in MANUAL mode -> arm */
if (sp_man.r > STICK_ON_OFF_LIMIT && sp_man.z < 0.1f && status.rc_input_mode != vehicle_status_s::RC_IN_MODE_OFF ) {
if (stick_on_counter > STICK_ON_OFF_COUNTER_LIMIT) {
/* we check outside of the transition function here because the requirement
* for being in manual mode only applies to manual arming actions.
* the system can be armed in auto if armed via the GCS.
*/
2015-09-27 19:49:01 -04:00
2015-05-17 12:58:44 +02:00
if ((status.main_state != vehicle_status_s::MAIN_STATE_MANUAL) &&
(status.main_state != vehicle_status_s::MAIN_STATE_STAB)) {
print_reject_arm("NOT ARMING: Switch to MANUAL mode first.");
2015-09-27 19:49:01 -04:00
} else if (!status.condition_home_position_valid &&
geofence_action == geofence_result_s::GF_ACTION_RTL) {
print_reject_arm("NOT ARMING: Geofence RTL requires valid home");
2015-09-04 19:57:44 +02:00
} else if (status.arming_state == vehicle_status_s::ARMING_STATE_STANDBY) {
arming_ret = arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_ARMED, &armed, true /* fRunPreArmChecks */,
mavlink_fd);
if (arming_ret == TRANSITION_CHANGED) {
arming_state_changed = true;
} else {
print_reject_arm("NOT ARMING: Configuration error");
}
2013-07-28 23:12:16 +04:00
}
stick_on_counter = 0;
} else {
stick_on_counter++;
2013-07-28 23:12:16 +04:00
}
} else {
stick_on_counter = 0;
}
if (arming_ret == TRANSITION_CHANGED) {
if (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
mavlink_log_info(mavlink_fd, "ARMED by RC");
} else {
mavlink_log_info(mavlink_fd, "DISARMED by RC");
2013-02-20 10:38:06 -08:00
}
arming_state_changed = true;
2013-02-20 10:38:06 -08:00
} else if (arming_ret == TRANSITION_DENIED) {
/*
* the arming transition can be denied to a number of reasons:
* - pre-flight check failed (sensors not ok or not calibrated)
* - safety not disabled
* - system not in manual mode
*/
tune_negative(true);
}
/* evaluate the main state machine according to mode switches */
transition_result_t main_res = set_main_state_rc(&status, &sp_man);
2013-07-28 23:12:16 +04:00
2014-02-11 00:24:40 +01:00
/* play tune on mode change only if armed, blink LED always */
if (main_res == TRANSITION_CHANGED) {
2014-02-11 00:24:40 +01:00
tune_positive(armed.armed);
main_state_changed = true;
} else if (main_res == TRANSITION_DENIED) {
/* DENIED here indicates bug in the commander */
mavlink_log_critical(mavlink_fd, "main state transition denied");
}
2015-12-18 21:21:51 -07:00
/* check throttle kill switch */
if (sp_man.kill_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
/* set lockdown flag */
armed.lockdown = true;
} else if (sp_man.kill_switch == manual_control_setpoint_s::SWITCH_POS_OFF) {
armed.lockdown = false;
2015-12-18 21:21:51 -07:00
}
/* no else case: do not change lockdown flag in unconfigured case */
2015-12-18 21:21:51 -07:00
} else {
2015-09-04 19:57:44 +02:00
if (!status.rc_input_blocked && !status.rc_signal_lost) {
mavlink_log_critical(mavlink_fd, "MANUAL CONTROL LOST (at t=%llums)", hrt_absolute_time() / 1000);
status.rc_signal_lost = true;
2015-01-16 16:46:16 +01:00
status.rc_signal_lost_timestamp = sp_man.timestamp;
status_changed = true;
}
}
/* data links check */
bool have_link = false;
2015-07-12 12:34:48 +02:00
for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
if (telemetry_last_heartbeat[i] != 0 &&
hrt_elapsed_time(&telemetry_last_heartbeat[i]) < datalink_loss_timeout * 1e6) {
/* handle the case where data link was gained first time or regained,
* accept datalink as healthy only after datalink_regain_timeout seconds
* */
if (telemetry_lost[i] &&
hrt_elapsed_time(&telemetry_last_dl_loss[i]) > datalink_regain_timeout * 1e6) {
/* report a regain */
if (telemetry_last_dl_loss[i] > 0) {
mavlink_and_console_log_info(mavlink_fd, "data link #%i regained", i);
2015-11-19 17:48:39 +01:00
} else if (telemetry_last_dl_loss[i] == 0) {
/* new link */
}
/* got link again or new */
status.condition_system_prearm_error_reported = false;
status_changed = true;
telemetry_lost[i] = false;
have_link = true;
} else if (!telemetry_lost[i]) {
2014-08-16 10:52:01 +02:00
/* telemetry was healthy also in last iteration
* we don't have to check a timeout */
2014-08-16 10:52:01 +02:00
have_link = true;
}
} else {
if (!telemetry_lost[i]) {
/* only reset the timestamp to a different time on state change */
telemetry_last_dl_loss[i] = hrt_absolute_time();
mavlink_and_console_log_info(mavlink_fd, "data link #%i lost", i);
telemetry_lost[i] = true;
}
}
}
if (have_link) {
2014-06-18 19:01:41 +02:00
/* handle the case where data link was regained */
if (status.data_link_lost) {
status.data_link_lost = false;
status_changed = true;
}
} else {
if (!status.data_link_lost) {
if (armed.armed) {
mavlink_and_console_log_critical(mavlink_fd, "ALL DATA LINKS LOST");
}
2014-06-18 19:01:41 +02:00
status.data_link_lost = true;
2014-07-20 18:23:41 +02:00
status.data_link_lost_counter++;
status_changed = true;
}
}
2014-09-05 08:59:00 +02:00
/* Check engine failure
* only for fixed wing for now
*/
if (!status.circuit_breaker_engaged_enginefailure_check &&
status.is_rotary_wing == false &&
armed.armed &&
((actuator_controls.control[3] > ef_throttle_thres &&
battery.current_a / actuator_controls.control[3] <
ef_current2throttle_thres) ||
(status.engine_failure))) {
2014-09-05 08:59:00 +02:00
/* potential failure, measure time */
if (timestamp_engine_healthy > 0 &&
hrt_elapsed_time(&timestamp_engine_healthy) >
ef_time_thres * 1e6 &&
!status.engine_failure) {
status.engine_failure = true;
status_changed = true;
mavlink_log_critical(mavlink_fd, "Engine Failure");
2014-09-05 08:59:00 +02:00
}
2014-09-05 08:59:00 +02:00
} else {
/* no failure reset flag */
timestamp_engine_healthy = hrt_absolute_time();
2014-09-05 08:59:00 +02:00
if (status.engine_failure) {
status.engine_failure = false;
status_changed = true;
}
}
/* reset main state after takeoff or land has been completed */
/* only switch back to at least altitude controlled modes */
if (status.main_state_prev == vehicle_status_s::MAIN_STATE_POSCTL ||
status.main_state_prev == vehicle_status_s::MAIN_STATE_ALTCTL) {
if ((status.main_state == vehicle_status_s::MAIN_STATE_AUTO_TAKEOFF
&& mission_result.finished) ||
(status.main_state == vehicle_status_s::MAIN_STATE_AUTO_LAND
&& status.condition_landed)) {
main_state_transition(&status, status.main_state_prev);
}
}
2014-09-05 08:59:00 +02:00
/* handle commands last, as the system needs to be updated to handle them */
orb_check(cmd_sub, &updated);
if (updated) {
/* got command */
orb_copy(ORB_ID(vehicle_command), cmd_sub, &cmd);
/* handle it */
2015-12-12 13:01:49 +01:00
if (handle_command(&status, &safety, &cmd, &armed, &_home, &global_position, &local_position,
&attitude, &home_pub, &command_ack_pub, &command_ack)) {
status_changed = true;
2014-05-11 13:36:51 +02:00
}
}
/* Check for failure combinations which lead to flight termination */
if (armed.armed) {
/* At this point the data link and the gps system have been checked
2015-09-27 19:49:01 -04:00
* If we are not in a manual (RC stick controlled mode)
* and both failed we want to terminate the flight */
if (status.main_state !=vehicle_status_s::MAIN_STATE_MANUAL &&
status.main_state !=vehicle_status_s::MAIN_STATE_ACRO &&
status.main_state !=vehicle_status_s::MAIN_STATE_RATTITUDE &&
2015-05-17 12:58:44 +02:00
status.main_state !=vehicle_status_s::MAIN_STATE_STAB &&
status.main_state !=vehicle_status_s::MAIN_STATE_ALTCTL &&
status.main_state !=vehicle_status_s::MAIN_STATE_POSCTL &&
((status.data_link_lost && status.gps_failure) ||
(status.data_link_lost_cmd && status.gps_failure_cmd))) {
armed.force_failsafe = true;
status_changed = true;
static bool flight_termination_printed = false;
if (!flight_termination_printed) {
warnx("Flight termination because of data link loss && gps failure");
mavlink_log_critical(mavlink_fd, "DL and GPS lost: flight termination");
flight_termination_printed = true;
}
if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) {
mavlink_log_critical(mavlink_fd, "DL and GPS lost: flight termination");
}
}
/* At this point the rc signal and the gps system have been checked
* If we are in manual (controlled with RC):
* if both failed we want to terminate the flight */
if ((status.main_state ==vehicle_status_s::MAIN_STATE_ACRO ||
status.main_state ==vehicle_status_s::MAIN_STATE_RATTITUDE ||
status.main_state ==vehicle_status_s::MAIN_STATE_MANUAL ||
status.main_state ==vehicle_status_s::MAIN_STATE_STAB ||
status.main_state ==vehicle_status_s::MAIN_STATE_ALTCTL ||
status.main_state ==vehicle_status_s::MAIN_STATE_POSCTL) &&
((status.rc_signal_lost && status.gps_failure) ||
(status.rc_signal_lost_cmd && status.gps_failure_cmd))) {
armed.force_failsafe = true;
status_changed = true;
static bool flight_termination_printed = false;
if (!flight_termination_printed) {
warnx("Flight termination because of RC signal loss && gps failure");
flight_termination_printed = true;
}
if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) {
mavlink_log_critical(mavlink_fd, "RC and GPS lost: flight termination");
}
}
}
/* Get current timestamp */
const hrt_abstime now = hrt_absolute_time();
/* First time home position update - but only if disarmed */
if (!status.condition_home_position_valid && !armed.armed) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude);
}
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
2015-10-27 09:36:09 +01:00
else if (((!was_armed && armed.armed) || (was_landed && !status.condition_landed)) &&
(now > commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL)) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude);
}
2015-10-24 19:14:23 +02:00
was_landed = status.condition_landed;
2015-10-27 09:36:09 +01:00
was_armed = armed.armed;
/* print new state */
if (arming_state_changed) {
status_changed = true;
arming_state_changed = false;
}
2014-05-11 13:36:51 +02:00
/* now set navigation state according to failsafe and main state */
2014-06-18 19:01:41 +02:00
bool nav_state_changed = set_nav_state(&status, (bool)datalink_loss_enabled,
mission_result.finished,
mission_result.stay_in_failsafe);
if (status.failsafe != failsafe_old) {
status_changed = true;
2015-01-16 16:46:16 +01:00
if (status.failsafe) {
mavlink_log_critical(mavlink_fd, "failsafe mode on");
2015-01-16 16:46:16 +01:00
} else {
mavlink_log_critical(mavlink_fd, "failsafe mode off");
}
2015-01-16 16:46:16 +01:00
failsafe_old = status.failsafe;
}
2015-06-08 15:19:41 +02:00
// TODO handle mode changes by commands
if (main_state_changed || nav_state_changed) {
status_changed = true;
2015-06-08 15:19:41 +02:00
main_state_changed = false;
}
2013-03-26 10:44:49 -07:00
/* publish states (armed, control mode, vehicle status) at least with 5 Hz */
if (counter % (200000 / COMMANDER_MONITORING_INTERVAL) == 0 || status_changed) {
set_control_mode();
control_mode.timestamp = now;
orb_publish(ORB_ID(vehicle_control_mode), control_mode_pub, &control_mode);
status.timestamp = now;
2013-07-28 23:12:16 +04:00
orb_publish(ORB_ID(vehicle_status), status_pub, &status);
armed.timestamp = now;
2015-07-22 12:42:50 +02:00
/* set prearmed state if safety is off, or safety is not present and 5 seconds passed */
if (safety.safety_switch_available) {
/* safety is off, go into prearmed */
armed.prearmed = safety.safety_off;
} else {
/* safety is not present, go into prearmed
* (all output drivers should be started / unlocked last in the boot process
* when the rest of the system is fully initialized)
*/
armed.prearmed = (hrt_elapsed_time(&commander_boot_timestamp) > 5 * 1000 * 1000);
}
orb_publish(ORB_ID(actuator_armed), armed_pub, &armed);
2012-08-16 15:49:56 +02:00
}
/* play arming and battery warning tunes */
if (!arm_tune_played && armed.armed && (!safety.safety_switch_available || (safety.safety_switch_available
&& safety.safety_off))) {
/* play tune when armed */
2014-02-11 00:24:40 +01:00
set_tune(TONE_ARMING_WARNING_TUNE);
2014-02-11 18:24:20 +01:00
arm_tune_played = true;
2013-07-28 23:12:16 +04:00
2015-05-30 19:06:05 -07:00
} else if ((status.hil_state != vehicle_status_s::HIL_STATE_ON) &&
status.battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL) {
/* play tune on battery critical */
2014-02-11 00:24:40 +01:00
set_tune(TONE_BATTERY_WARNING_FAST_TUNE);
2013-07-28 23:12:16 +04:00
2015-05-30 19:06:05 -07:00
} else if ((status.hil_state != vehicle_status_s::HIL_STATE_ON) &&
(status.battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_LOW || status.failsafe)) {
/* play tune on battery warning or failsafe */
set_tune(TONE_BATTERY_WARNING_SLOW_TUNE);
2013-07-28 23:12:16 +04:00
2014-02-11 18:24:20 +01:00
} else {
2014-02-11 00:24:40 +01:00
set_tune(TONE_STOP_TUNE);
}
/* reset arm_tune_played when disarmed */
2014-02-11 18:24:20 +01:00
if (!armed.armed || (safety.safety_switch_available && !safety.safety_off)) {
//Notify the user that it is safe to approach the vehicle
2015-01-16 16:46:16 +01:00
if (arm_tune_played) {
tune_neutral(true);
}
arm_tune_played = false;
}
/* play sensor failure tunes if we already waited for hotplug sensors to come up and failed */
hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
if (!sensor_fail_tune_played && (!status.condition_system_sensors_initialized && hotplug_timeout)) {
set_tune_override(TONE_GPS_WARNING_TUNE);
sensor_fail_tune_played = true;
status_changed = true;
}
/* update timeout flag */
if(!(hotplug_timeout == status.condition_system_hotplug_timeout)) {
status.condition_system_hotplug_timeout = hotplug_timeout;
status_changed = true;
}
counter++;
int blink_state = blink_msg_state();
if (blink_state > 0) {
/* blinking LED message, don't touch LEDs */
if (blink_state == 2) {
/* blinking LED message completed, restore normal state */
control_status_leds(&status, &armed, true);
}
} else {
/* normal state */
control_status_leds(&status, &armed, status_changed);
}
status_changed = false;
usleep(COMMANDER_MONITORING_INTERVAL);
}
/* wait for threads to complete */
ret = pthread_join(commander_low_prio_thread, NULL);
if (ret) {
warn("join failed: %d", ret);
}
rgbled_set_mode(RGBLED_MODE_OFF);
/* close fds */
led_deinit();
buzzer_deinit();
px4_close(sp_man_sub);
px4_close(offboard_control_mode_sub);
px4_close(local_position_sub);
px4_close(global_position_sub);
px4_close(gps_sub);
px4_close(sensor_sub);
px4_close(safety_sub);
px4_close(cmd_sub);
px4_close(subsys_sub);
px4_close(diff_pres_sub);
px4_close(param_changed_sub);
px4_close(battery_sub);
thread_running = false;
return 0;
}
void
get_circuit_breaker_params()
{
status.circuit_breaker_engaged_power_check =
circuit_breaker_enabled("CBRK_SUPPLY_CHK", CBRK_SUPPLY_CHK_KEY);
status.cb_usb =
circuit_breaker_enabled("CBRK_USB_CHK", CBRK_USB_CHK_KEY);
status.circuit_breaker_engaged_airspd_check =
circuit_breaker_enabled("CBRK_AIRSPD_CHK", CBRK_AIRSPD_CHK_KEY);
status.circuit_breaker_engaged_enginefailure_check =
circuit_breaker_enabled("CBRK_ENGINEFAIL", CBRK_ENGINEFAIL_KEY);
status.circuit_breaker_engaged_gpsfailure_check =
circuit_breaker_enabled("CBRK_GPSFAIL", CBRK_GPSFAIL_KEY);
}
2013-08-19 09:53:00 +02:00
void
check_valid(hrt_abstime timestamp, hrt_abstime timeout, bool valid_in, bool *valid_out, bool *changed)
{
hrt_abstime t = hrt_absolute_time();
bool valid_new = (t < timestamp + timeout && t > timeout && valid_in);
if (*valid_out != valid_new) {
*valid_out = valid_new;
*changed = true;
}
}
void
control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actuator_armed, bool changed)
{
/* driving rgbled */
if (changed) {
bool set_normal_color = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* set mode */
if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
rgbled_set_mode(RGBLED_MODE_ON);
set_normal_color = true;
} else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED_ERROR || (!status.condition_system_sensors_initialized && hotplug_timeout)) {
rgbled_set_mode(RGBLED_MODE_BLINK_FAST);
rgbled_set_color(RGBLED_COLOR_RED);
} else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_STANDBY) {
rgbled_set_mode(RGBLED_MODE_BREATHE);
set_normal_color = true;
} else if (!status.condition_system_sensors_initialized && !hotplug_timeout) {
rgbled_set_mode(RGBLED_MODE_BREATHE);
set_normal_color = true;
} else { // STANDBY_ERROR and other states
rgbled_set_mode(RGBLED_MODE_BLINK_NORMAL);
rgbled_set_color(RGBLED_COLOR_RED);
}
if (set_normal_color) {
/* set color */
if (status_local->failsafe) {
rgbled_set_color(RGBLED_COLOR_PURPLE);
} else if (status_local->battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_LOW) {
rgbled_set_color(RGBLED_COLOR_AMBER);
} else if (status_local->battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL) {
rgbled_set_color(RGBLED_COLOR_RED);
} else {
2015-11-11 15:35:55 +05:30
if (status_local->condition_home_position_valid && status_local->condition_global_position_valid) {
rgbled_set_color(RGBLED_COLOR_GREEN);
} else {
rgbled_set_color(RGBLED_COLOR_BLUE);
}
}
}
}
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V1) || defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
2013-08-27 23:08:00 +02:00
/* this runs at around 20Hz, full cycle is 16 ticks = 10/16Hz */
if (actuator_armed->armed) {
/* armed, solid */
led_on(LED_BLUE);
} else if (actuator_armed->ready_to_arm) {
/* ready to arm, blink at 1Hz */
2014-05-11 13:36:51 +02:00
if (leds_counter % 20 == 0) {
led_toggle(LED_BLUE);
2014-05-11 13:36:51 +02:00
}
2013-08-27 23:08:00 +02:00
} else {
/* not ready to arm, blink at 10Hz */
2014-05-11 13:36:51 +02:00
if (leds_counter % 2 == 0) {
led_toggle(LED_BLUE);
2014-05-11 13:36:51 +02:00
}
}
2013-08-27 23:08:00 +02:00
#endif
/* give system warnings on error LED, XXX maybe add memory usage warning too */
if (status_local->load > 0.95f) {
2014-05-11 13:36:51 +02:00
if (leds_counter % 2 == 0) {
led_toggle(LED_AMBER);
2014-05-11 13:36:51 +02:00
}
2013-08-27 23:08:00 +02:00
} else {
led_off(LED_AMBER);
}
leds_counter++;
}
2013-07-28 23:12:16 +04:00
transition_result_t
set_main_state_rc(struct vehicle_status_s *status_local, struct manual_control_setpoint_s *sp_man)
2013-07-28 23:12:16 +04:00
{
/* set main state according to RC switches */
2013-07-28 23:12:16 +04:00
transition_result_t res = TRANSITION_DENIED;
2015-09-27 19:49:01 -04:00
/* if offboard is set already by a mavlink command, abort */
if (status.offboard_control_set_by_command) {
return main_state_transition(status_local,vehicle_status_s::MAIN_STATE_OFFBOARD);
}
/* manual setpoint has not updated, do not re-evaluate it */
if ((_last_sp_man.timestamp == sp_man->timestamp) ||
((_last_sp_man.offboard_switch == sp_man->offboard_switch) &&
(_last_sp_man.return_switch == sp_man->return_switch) &&
(_last_sp_man.mode_switch == sp_man->mode_switch) &&
(_last_sp_man.acro_switch == sp_man->acro_switch) &&
(_last_sp_man.rattitude_switch == sp_man->rattitude_switch) &&
(_last_sp_man.posctl_switch == sp_man->posctl_switch) &&
(_last_sp_man.loiter_switch == sp_man->loiter_switch))) {
2015-09-27 19:49:01 -04:00
// update these fields for the geofence system
_last_sp_man.timestamp = sp_man->timestamp;
_last_sp_man.x = sp_man->x;
_last_sp_man.y = sp_man->y;
_last_sp_man.z = sp_man->z;
_last_sp_man.r = sp_man->r;
/* no timestamp change or no switch change -> nothing changed */
return TRANSITION_NOT_CHANGED;
}
2015-09-27 19:49:01 -04:00
_last_sp_man = *sp_man;
2014-01-29 21:21:16 +01:00
/* offboard switch overrides main switch */
if (sp_man->offboard_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_OFFBOARD);
2014-01-29 21:21:16 +01:00
if (res == TRANSITION_DENIED) {
print_reject_mode(status_local, "OFFBOARD");
/* mode rejected, continue to evaluate the main system mode */
2013-07-28 23:12:16 +04:00
2014-01-29 21:21:16 +01:00
} else {
/* changed successfully or already in this state */
2014-01-29 21:21:16 +01:00
return res;
}
}
2013-07-28 23:12:16 +04:00
/* RTL switch overrides main switch */
if (sp_man->return_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_AUTO_RTL);
if (res == TRANSITION_DENIED) {
print_reject_mode(status_local, "AUTO_RTL");
/* fallback to LOITER if home position not set */
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_AUTO_LOITER);
2015-04-20 22:00:36 +02:00
}
2015-04-20 22:00:36 +02:00
if (res != TRANSITION_DENIED) {
/* changed successfully or already in this state */
2014-01-29 21:21:16 +01:00
return res;
}
2015-04-20 22:00:36 +02:00
/* if we get here mode was rejected, continue to evaluate the main system mode */
2014-01-29 21:21:16 +01:00
}
2013-07-28 23:12:16 +04:00
/* offboard and RTL switches off or denied, check main mode switch */
switch (sp_man->mode_switch) {
case manual_control_setpoint_s::SWITCH_POS_NONE:
res = TRANSITION_NOT_CHANGED;
break;
case manual_control_setpoint_s::SWITCH_POS_OFF: // MANUAL
if (sp_man->acro_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
2015-05-17 12:58:44 +02:00
/* manual mode is stabilized already for multirotors, so switch to acro
* for any non-manual mode
*/
if (status.is_rotary_wing) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_ACRO);
} else {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_STAB);
}
2014-05-20 00:03:00 +02:00
}
else if(sp_man->rattitude_switch == manual_control_setpoint_s::SWITCH_POS_ON){
/* Similar to acro transitions for multirotors. FW aircraft don't need a
* rattitude mode.*/
if (status.is_rotary_wing) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_RATTITUDE);
} else {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_STAB);
}
}else {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_MANUAL);
2014-01-31 22:44:05 +01:00
}
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break;
case manual_control_setpoint_s::SWITCH_POS_MIDDLE: // ASSIST
if (sp_man->posctl_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_POSCTL);
2013-07-28 23:12:16 +04:00
if (res != TRANSITION_DENIED) {
2013-07-28 23:12:16 +04:00
break; // changed successfully or already in this state
}
2013-07-28 23:12:16 +04:00
print_reject_mode(status_local, "POSCTL");
2013-07-28 23:12:16 +04:00
}
// fallback to ALTCTL
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_ALTCTL);
2013-07-28 23:12:16 +04:00
if (res != TRANSITION_DENIED) {
2013-07-28 23:12:16 +04:00
break; // changed successfully or already in this mode
}
2013-07-28 23:12:16 +04:00
if (sp_man->posctl_switch != manual_control_setpoint_s::SWITCH_POS_ON) {
print_reject_mode(status_local, "ALTCTL");
}
// fallback to MANUAL
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_MANUAL);
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break;
case manual_control_setpoint_s::SWITCH_POS_ON: // AUTO
if (sp_man->loiter_switch == manual_control_setpoint_s::SWITCH_POS_ON) {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_AUTO_LOITER);
if (res != TRANSITION_DENIED) {
break; // changed successfully or already in this state
}
print_reject_mode(status_local, "AUTO_LOITER");
} else {
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_AUTO_MISSION);
if (res != TRANSITION_DENIED) {
break; // changed successfully or already in this state
}
print_reject_mode(status_local, "AUTO_MISSION");
// fallback to LOITER if home position not set
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_AUTO_LOITER);
if (res != TRANSITION_DENIED) {
break; // changed successfully or already in this state
}
}
2013-07-28 23:12:16 +04:00
// fallback to POSCTL
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_POSCTL);
if (res != TRANSITION_DENIED) {
break; // changed successfully or already in this state
}
// fallback to ALTCTL
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_ALTCTL);
2013-07-28 23:12:16 +04:00
if (res != TRANSITION_DENIED) {
2013-07-28 23:12:16 +04:00
break; // changed successfully or already in this state
}
2013-07-28 23:12:16 +04:00
// fallback to MANUAL
res = main_state_transition(status_local,vehicle_status_s::MAIN_STATE_MANUAL);
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break;
default:
break;
}
return res;
}
void
set_control_mode()
{
/* set vehicle_control_mode according to set_navigation_state */
control_mode.flag_armed = armed.armed;
2014-12-23 21:50:16 +01:00
control_mode.flag_external_manual_override_ok = (!status.is_rotary_wing && !status.is_vtol);
control_mode.flag_system_hil_enabled = status.hil_state == vehicle_status_s::HIL_STATE_ON;
control_mode.flag_control_offboard_enabled = false;
switch (status.nav_state) {
case vehicle_status_s::NAVIGATION_STATE_MANUAL:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = stabilization_required();
control_mode.flag_control_attitude_enabled = stabilization_required();
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = false;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
break;
2015-05-17 12:58:44 +02:00
case vehicle_status_s::NAVIGATION_STATE_STAB:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = false;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
/* override is not ok in stabilized mode */
control_mode.flag_external_manual_override_ok = false;
2015-05-17 12:58:44 +02:00
break;
case vehicle_status_s::NAVIGATION_STATE_RATTITUDE:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = false;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_ALTCTL:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = true;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_POSCTL:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = true;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_position_enabled = !status.in_transition_mode;
control_mode.flag_control_velocity_enabled = !status.in_transition_mode;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_RTL:
case vehicle_status_s::NAVIGATION_STATE_AUTO_RCRECOVER:
/* override is not ok for the RTL and recovery mode */
control_mode.flag_external_manual_override_ok = false;
/* fallthrough */
case vehicle_status_s::NAVIGATION_STATE_AUTO_RTGS:
case vehicle_status_s::NAVIGATION_STATE_AUTO_LANDENGFAIL:
case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION:
case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER:
2015-11-22 16:03:58 +01:00
case vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF:
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = true;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = true;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_position_enabled = !status.in_transition_mode;
control_mode.flag_control_velocity_enabled = !status.in_transition_mode;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_LANDGPSFAIL:
2014-08-22 00:40:45 +02:00
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_ACRO:
control_mode.flag_control_manual_enabled = true;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = false;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = false;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_LAND:
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = true;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
/* in failsafe LAND mode position may be not available */
control_mode.flag_control_position_enabled = status.condition_local_position_valid;
control_mode.flag_control_velocity_enabled = status.condition_local_position_valid;
control_mode.flag_control_altitude_enabled = true;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_DESCEND:
/* TODO: check if this makes sense */
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = true;
control_mode.flag_control_rates_enabled = true;
control_mode.flag_control_attitude_enabled = true;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = true;
control_mode.flag_control_termination_enabled = false;
break;
case vehicle_status_s::NAVIGATION_STATE_TERMINATION:
/* disable all controllers on termination */
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_rates_enabled = false;
control_mode.flag_control_attitude_enabled = false;
control_mode.flag_control_position_enabled = false;
control_mode.flag_control_velocity_enabled = false;
control_mode.flag_control_altitude_enabled = false;
control_mode.flag_control_climb_rate_enabled = false;
control_mode.flag_control_termination_enabled = true;
break;
case vehicle_status_s::NAVIGATION_STATE_OFFBOARD:
control_mode.flag_control_manual_enabled = false;
control_mode.flag_control_auto_enabled = false;
control_mode.flag_control_offboard_enabled = true;
/*
* The control flags depend on what is ignored according to the offboard control mode topic
* Inner loop flags (e.g. attitude) also depend on outer loop ignore flags (e.g. position)
*/
control_mode.flag_control_rates_enabled = !offboard_control_mode.ignore_bodyrate ||
!offboard_control_mode.ignore_attitude ||
!offboard_control_mode.ignore_position ||
!offboard_control_mode.ignore_velocity ||
!offboard_control_mode.ignore_acceleration_force;
control_mode.flag_control_attitude_enabled = !offboard_control_mode.ignore_attitude ||
!offboard_control_mode.ignore_position ||
!offboard_control_mode.ignore_velocity ||
!offboard_control_mode.ignore_acceleration_force;
control_mode.flag_control_velocity_enabled = (!offboard_control_mode.ignore_velocity ||
!offboard_control_mode.ignore_position) && !status.in_transition_mode;
control_mode.flag_control_climb_rate_enabled = !offboard_control_mode.ignore_velocity ||
!offboard_control_mode.ignore_position;
control_mode.flag_control_position_enabled = !offboard_control_mode.ignore_position && !status.in_transition_mode;
control_mode.flag_control_altitude_enabled = !offboard_control_mode.ignore_velocity ||
!offboard_control_mode.ignore_position;
2015-01-16 16:46:16 +01:00
break;
default:
break;
}
}
bool
stabilization_required()
{
return (status.is_rotary_wing || // is a rotary wing, or
status.vtol_fw_permanent_stab || // is a VTOL in fixed wing mode and stabilisation is on, or
(vtol_status.vtol_in_trans_mode && // is currently a VTOL transitioning AND
!status.is_rotary_wing)); // is a fixed wing, ie: transitioning back to rotary wing mode
}
void
print_reject_mode(struct vehicle_status_s *status_local, const char *msg)
{
hrt_abstime t = hrt_absolute_time();
if (t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL) {
last_print_mode_reject_time = t;
mavlink_log_critical(mavlink_fd, "REJECT %s", msg);
2014-02-11 00:24:40 +01:00
/* only buzz if armed, because else we're driving people nuts indoors
they really need to look at the leds as well. */
tune_negative(armed.armed);
}
}
void
print_reject_arm(const char *msg)
{
hrt_abstime t = hrt_absolute_time();
if (t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL) {
last_print_mode_reject_time = t;
mavlink_log_critical(mavlink_fd, msg);
2014-02-11 00:24:40 +01:00
tune_negative(true);
}
}
2015-12-12 13:01:49 +01:00
void answer_command(struct vehicle_command_s &cmd, unsigned result,
orb_advert_t &command_ack_pub, vehicle_command_ack_s &command_ack)
{
switch (result) {
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED:
2015-01-16 16:46:16 +01:00
tune_positive(true);
2013-08-27 23:08:00 +02:00
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_RESULT_DENIED:
mavlink_log_critical(mavlink_fd, "command denied: %u", cmd.command);
2014-02-11 00:24:40 +01:00
tune_negative(true);
2013-08-27 23:08:00 +02:00
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_RESULT_FAILED:
mavlink_log_critical(mavlink_fd, "command failed: %u", cmd.command);
2014-02-11 00:24:40 +01:00
tune_negative(true);
2013-08-27 23:08:00 +02:00
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED:
/* this needs additional hints to the user - so let other messages pass and be spoken */
mavlink_log_critical(mavlink_fd, "command temporarily rejected: %u", cmd.command);
2014-02-11 00:24:40 +01:00
tune_negative(true);
2013-08-27 23:08:00 +02:00
break;
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_RESULT_UNSUPPORTED:
mavlink_log_critical(mavlink_fd, "command unsupported: %u", cmd.command);
2014-02-11 00:24:40 +01:00
tune_negative(true);
2013-08-27 23:08:00 +02:00
break;
default:
break;
}
2015-12-12 13:01:49 +01:00
/* publish ACK */
command_ack.command = cmd.command;
command_ack.result = result;
if (command_ack_pub != nullptr) {
orb_publish(ORB_ID(vehicle_command_ack), command_ack_pub, &command_ack);
} else {
command_ack_pub = orb_advertise(ORB_ID(vehicle_command_ack), &command_ack);
}
}
2013-03-26 10:44:49 -07:00
void *commander_low_prio_loop(void *arg)
{
/* Set thread name */
px4_prctl(PR_SET_NAME, "commander_low_prio", px4_getpid());
/* Subscribe to command topic */
int cmd_sub = orb_subscribe(ORB_ID(vehicle_command));
struct vehicle_command_s cmd;
memset(&cmd, 0, sizeof(cmd));
2015-12-12 13:01:49 +01:00
/* command ack */
orb_advert_t command_ack_pub = nullptr;
struct vehicle_command_ack_s command_ack;
memset(&command_ack, 0, sizeof(command_ack));
2015-03-23 10:52:32 -07:00
/* timeout for param autosave */
hrt_abstime need_param_autosave_timeout = 0;
2015-03-23 10:52:32 -07:00
/* wakeup source(s) */
px4_pollfd_struct_t fds[1];
/* use the gyro to pace output - XXX BROKEN if we are using the L3GD20 */
fds[0].fd = cmd_sub;
fds[0].events = POLLIN;
while (!thread_should_exit) {
/* wait for up to 1000ms for data */
int pret = px4_poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 1000);
/* timed out - periodic check for thread_should_exit, etc. */
2014-05-11 13:36:51 +02:00
if (pret == 0) {
/* trigger a param autosave if required */
if (need_param_autosave) {
if (need_param_autosave_timeout > 0 && hrt_elapsed_time(&need_param_autosave_timeout) > 200000ULL) {
int ret = param_save_default();
2015-11-02 18:48:53 +01:00
if (ret != OK) {
mavlink_and_console_log_critical(mavlink_fd, "settings auto save error");
} else {
warnx("settings saved.");
}
need_param_autosave = false;
need_param_autosave_timeout = 0;
} else {
need_param_autosave_timeout = hrt_absolute_time();
}
}
} else if (pret < 0) {
/* this is undesirable but not much we can do - might want to flag unhappy status */
warn("commander: poll error %d, %d", pret, errno);
continue;
} else {
/* if we reach here, we have a valid command */
orb_copy(ORB_ID(vehicle_command), cmd_sub, &cmd);
/* ignore commands the high-prio loop handles */
2015-05-26 22:55:14 -07:00
if (cmd.command == vehicle_command_s::VEHICLE_CMD_DO_SET_MODE ||
cmd.command == vehicle_command_s::VEHICLE_CMD_COMPONENT_ARM_DISARM ||
cmd.command == vehicle_command_s::VEHICLE_CMD_NAV_TAKEOFF ||
cmd.command == vehicle_command_s::VEHICLE_CMD_DO_SET_SERVO) {
continue;
}
/* only handle low-priority commands here */
switch (cmd.command) {
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
if (is_safe(&status, &safety, &armed)) {
if (((int)(cmd.param1)) == 1) {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
usleep(100000);
/* reboot */
px4_systemreset(false);
} else if (((int)(cmd.param1)) == 3) {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
usleep(100000);
/* reboot to bootloader */
px4_systemreset(true);
2013-08-27 23:08:00 +02:00
} else {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_DENIED, command_ack_pub, command_ack);
}
2013-08-27 23:08:00 +02:00
} else {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_DENIED, command_ack_pub, command_ack);
}
break;
2013-08-27 23:08:00 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_CALIBRATION: {
int calib_ret = ERROR;
/* try to go to INIT/PREFLIGHT arming state */
if (TRANSITION_DENIED == arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_INIT, &armed,
false /* fRunPreArmChecks */, mavlink_fd)) {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_DENIED, command_ack_pub, command_ack);
break;
} else {
status.calibration_enabled = true;
}
if ((int)(cmd.param1) == 1) {
/* gyro calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_gyro_calibration(mavlink_fd);
} else if ((int)(cmd.param2) == 1) {
/* magnetometer calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_mag_calibration(mavlink_fd);
} else if ((int)(cmd.param3) == 1) {
/* zero-altitude pressure calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_DENIED, command_ack_pub, command_ack);
} else if ((int)(cmd.param4) == 1) {
/* RC calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
/* disable RC control input completely */
status.rc_input_blocked = true;
calib_ret = OK;
mavlink_log_info(mavlink_fd, "CAL: Disabling RC IN");
} else if ((int)(cmd.param4) == 2) {
/* RC trim calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_trim_calibration(mavlink_fd);
} else if ((int)(cmd.param5) == 1) {
/* accelerometer calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_accel_calibration(mavlink_fd);
} else if ((int)(cmd.param5) == 2) {
// board offset calibration
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_level_calibration(mavlink_fd);
} else if ((int)(cmd.param6) == 1) {
/* airspeed calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
calib_ret = do_airspeed_calibration(mavlink_fd);
2015-04-28 14:54:58 +02:00
} else if ((int)(cmd.param7) == 1) {
/* do esc calibration */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
2015-05-22 09:28:52 -07:00
calib_ret = do_esc_calibration(mavlink_fd, &armed);
} else if ((int)(cmd.param4) == 0) {
/* RC calibration ended - have we been in one worth confirming? */
if (status.rc_input_blocked) {
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
/* enable RC control input */
status.rc_input_blocked = false;
mavlink_log_info(mavlink_fd, "CAL: Re-enabling RC IN");
calib_ret = OK;
}
2015-04-28 14:54:58 +02:00
/* this always succeeds */
calib_ret = OK;
}
status.calibration_enabled = false;
if (calib_ret == OK) {
tune_positive(true);
// Update preflight check status
// we do not set the calibration return value based on it because the calibration
// might have worked just fine, but the preflight check fails for a different reason,
// so this would be prone to false negatives.
bool checkAirspeed = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing */
if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) {
checkAirspeed = true;
}
2015-05-24 20:10:35 +02:00
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed,
!(status.rc_input_mode >= vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_STANDBY, &armed, false /* fRunPreArmChecks */, mavlink_fd);
} else {
tune_negative(true);
}
2014-05-11 13:36:51 +02:00
break;
2014-05-11 13:36:51 +02:00
}
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_STORAGE: {
if (((int)(cmd.param1)) == 0) {
int ret = param_load_default();
2013-07-28 23:12:16 +04:00
if (ret == OK) {
mavlink_log_info(mavlink_fd, "settings loaded");
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
2013-07-28 23:12:16 +04:00
} else {
mavlink_log_critical(mavlink_fd, "settings load ERROR");
/* convenience as many parts of NuttX use negative errno */
if (ret < 0) {
ret = -ret;
}
if (ret < 1000) {
mavlink_log_critical(mavlink_fd, "ERROR: %s", strerror(ret));
}
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_FAILED, command_ack_pub, command_ack);
2014-05-11 13:36:51 +02:00
}
} else if (((int)(cmd.param1)) == 1) {
int ret = param_save_default();
if (ret == OK) {
if (need_param_autosave) {
need_param_autosave = false;
need_param_autosave_timeout = 0;
}
/* do not spam MAVLink, but provide the answer / green led mechanism */
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
} else {
mavlink_log_critical(mavlink_fd, "settings save error");
/* convenience as many parts of NuttX use negative errno */
if (ret < 0) {
ret = -ret;
}
if (ret < 1000) {
mavlink_log_critical(mavlink_fd, "ERROR: %s", strerror(ret));
}
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_FAILED, command_ack_pub, command_ack);
}
} else if (((int)(cmd.param1)) == 2) {
/* reset parameters and save empty file */
param_reset_all();
int ret = param_save_default();
if (ret == OK) {
/* do not spam MAVLink, but provide the answer / green led mechanism */
mavlink_log_critical(mavlink_fd, "onboard parameters reset");
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED, command_ack_pub, command_ack);
} else {
mavlink_log_critical(mavlink_fd, "param reset error");
2015-12-12 13:01:49 +01:00
answer_command(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_FAILED, command_ack_pub, command_ack);
2014-05-11 13:36:51 +02:00
}
2013-08-27 23:08:00 +02:00
}
break;
}
2013-08-27 23:08:00 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s::VEHICLE_CMD_START_RX_PAIR:
/* handled in the IO driver */
2013-08-27 23:08:00 +02:00
break;
default:
/* don't answer on unsupported commands, it will be done in main loop */
break;
2015-03-23 10:52:32 -07:00
}
}
}
px4_close(cmd_sub);
2013-09-01 10:29:30 +02:00
return NULL;
}