2011-03-19 07:20:11 -03:00
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2010-12-19 12:40:33 -04:00
2013-01-30 11:30:46 -04:00
#define THISFIRMWARE "ArduCopter V2.9.1-dev"
2010-12-19 12:40:33 -04:00
/*
2012-12-10 11:24:34 -04:00
* ArduCopter Version 2.9
2012-08-21 23:19:50 -03:00
* Lead author: Jason Short
* Based on code and ideas from the Arducopter team: Randy Mackay, Pat Hickey, Jose Julio, Jani Hirvinen, Andrew Tridgell, Justin Beech, Adam Rivera, Jean-Louis Naudin, Roberto Navoni
* Thanks to: Chris Anderson, Mike Smith, Jordi Munoz, Doug Weibel, James Goppert, Benjamin Pelletier, Robert Lefebvre, Marco Robustini
*
* This firmware is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
2013-01-11 02:28:08 -04:00
* Special Thanks for Contributors (in alphabetical order by first name):
2012-08-21 23:19:50 -03:00
*
2013-01-11 02:28:08 -04:00
* Adam M Rivera :Auto Compass Declination
* Amilcar Lucas :Camera mount library
* Andrew Tridgell :General development, Mavlink Support
* Angel Fernandez :Alpha testing
2012-08-21 23:19:50 -03:00
* Doug Weibel :Libraries
* Christof Schmid :Alpha testing
2013-01-11 02:28:08 -04:00
* Dani Saez :V Octo Support
* Gregory Fletcher :Camera mount orientation math
2012-08-21 23:19:50 -03:00
* Guntars :Arming safety suggestion
2013-01-11 02:28:08 -04:00
* HappyKillmore :Mavlink GCS
* Hein Hollander :Octo Support
2012-08-21 23:19:50 -03:00
* Igor van Airde :Control Law optimization
2013-01-11 02:28:08 -04:00
* Leonard Hall :Flight Dynamics, INAV throttle
* Jonathan Challinger :Inertial Navigation
2012-08-21 23:19:50 -03:00
* Jean-Louis Naudin :Auto Landing
2013-01-11 02:28:08 -04:00
* Max Levine :Tri Support, Graphics
* Jack Dunkle :Alpha testing
* James Goppert :Mavlink Support
* Jani Hiriven :Testing feedback
2012-08-21 23:19:50 -03:00
* John Arne Birkeland :PPM Encoder
2013-01-11 02:28:08 -04:00
* Jose Julio :Stabilization Control laws
* Randy Mackay :General development and release
* Marco Robustini :Lead tester
* Michael Oborne :Mission Planner GCS
* Mike Smith :Libraries, Coding support
* Oliver :Piezo support
* Olivier Adler :PPM Encoder
2012-08-21 23:19:50 -03:00
* Robert Lefebvre :Heli Support & LEDs
2013-01-11 02:28:08 -04:00
* Sandro Benigno :Camera support
2012-08-21 23:19:50 -03:00
*
* And much more so PLEASE PM me on DIYDRONES to add your contribution to the List
*
* Requires modified "mrelax" version of Arduino, which can be found here:
* http://code.google.com/p/ardupilot-mega/downloads/list
*
*/
2010-12-19 12:40:33 -04:00
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// Header includes
////////////////////////////////////////////////////////////////////////////////
2012-12-12 21:25:09 -04:00
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
2012-12-12 19:46:20 -04:00
// Common dependencies
2010-12-19 12:40:33 -04:00
#include <AP_Common.h>
2012-10-27 00:55:17 -03:00
#include <AP_Progmem.h>
2012-10-19 00:53:39 -03:00
#include <AP_Menu.h>
2012-08-20 20:22:44 -03:00
#include <AP_Param.h>
2012-12-12 19:46:20 -04:00
// AP_HAL
#include <AP_HAL.h>
#include <AP_HAL_AVR.h>
#include <AP_HAL_AVR_SITL.h>
2013-01-08 14:32:48 -04:00
#include <AP_HAL_SMACCM.h>
2013-01-02 07:08:40 -04:00
#include <AP_HAL_PX4.h>
2012-12-18 06:15:11 -04:00
#include <AP_HAL_Empty.h>
2012-12-12 21:25:09 -04:00
2012-12-12 19:46:20 -04:00
// Application dependencies
#include <GCS_MAVLink.h> // MAVLink GCS definitions
2012-11-10 01:29:56 -04:00
#include <AP_GPS.h> // ArduPilot GPS library
#include <DataFlash.h> // ArduPilot Mega Flash Memory Library
#include <AP_ADC.h> // ArduPilot Mega Analog to Digital Converter Library
2012-12-12 20:16:32 -04:00
#include <AP_ADC_AnalogSource.h>
2011-11-27 01:35:23 -04:00
#include <AP_Baro.h>
2012-11-10 01:29:56 -04:00
#include <AP_Compass.h> // ArduPilot Mega Magnetometer Library
#include <AP_Math.h> // ArduPilot Mega Vector/Matrix math Library
#include <AP_Curve.h> // Curve used to linearlise throttle pwm to thrust
#include <AP_InertialSensor.h> // ArduPilot Mega Inertial Sensor (accel & gyro) Library
2012-03-11 05:36:12 -03:00
#include <AP_AHRS.h>
2012-08-21 23:19:50 -03:00
#include <APM_PI.h> // PI library
2012-11-10 01:29:56 -04:00
#include <AC_PID.h> // PID library
#include <RC_Channel.h> // RC Channel Library
2012-08-21 23:19:50 -03:00
#include <AP_Motors.h> // AP Motors library
#include <AP_RangeFinder.h> // Range finder library
2012-11-10 01:29:56 -04:00
#include <AP_OpticalFlow.h> // Optical Flow library
#include <Filter.h> // Filter library
#include <AP_Buffer.h> // APM FIFO Buffer
2012-08-21 23:19:50 -03:00
#include <AP_LeadFilter.h> // GPS Lead filter
#include <AP_Relay.h> // APM relay
#include <AP_Camera.h> // Photo or video camera
#include <AP_Mount.h> // Camera/Antenna mount
2012-11-10 01:29:56 -04:00
#include <AP_Airspeed.h> // needed for AHRS build
2012-11-07 09:24:00 -04:00
#include <AP_InertialNav.h> // ArduPilot Mega inertial navigation library
2012-12-12 19:46:20 -04:00
#include <AP_Declination.h> // ArduPilot Mega Declination Helper Library
#include <AP_Limits.h>
2013-01-11 21:01:10 -04:00
#include <memcheck.h> // memory limit checker
#include <SITL.h> // software in the loop support
#include <AP_Scheduler.h> // main loop scheduler
2011-04-13 13:33:06 -03:00
2012-12-12 20:16:32 -04:00
// AP_HAL to Arduino compatibility layer
#include "compat.h"
2010-12-19 12:40:33 -04:00
// Configuration
2011-06-24 01:37:54 -03:00
#include "defines.h"
2010-12-19 12:40:33 -04:00
#include "config.h"
2012-01-01 16:24:38 -04:00
#include "config_channels.h"
2010-12-19 12:40:33 -04:00
// Local modules
2011-02-17 03:09:13 -04:00
#include "Parameters.h"
2011-02-17 05:36:33 -04:00
#include "GCS.h"
2010-12-19 12:40:33 -04:00
2012-12-13 19:27:42 -04:00
////////////////////////////////////////////////////////////////////////////////
// cliSerial
////////////////////////////////////////////////////////////////////////////////
// cliSerial isn't strictly necessary - it is an alias for hal.console. It may
// be deprecated in favor of hal.console in later releases.
AP_HAL::BetterStream* cliSerial;
// N.B. we need to keep a static declaration which isn't guarded by macros
// at the top to cooperate with the prototype mangler.
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-12-12 19:46:20 -04:00
// AP_HAL instance
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-12-13 19:27:42 -04:00
2012-12-18 06:15:11 -04:00
const AP_HAL::HAL& hal = AP_HAL_BOARD_DRIVER;
2012-08-06 22:03:26 -03:00
2011-11-12 23:47:16 -04:00
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////
//
// Global parameters are all contained within the 'g' class.
//
2012-08-21 23:19:50 -03:00
static Parameters g;
2011-02-17 03:09:13 -04:00
2013-01-11 21:01:10 -04:00
// main loop scheduler
AP_Scheduler scheduler;
2011-05-09 14:40:32 -03:00
2011-03-17 22:50:46 -03:00
////////////////////////////////////////////////////////////////////////////////
// prototypes
2011-11-12 23:47:16 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-12-12 19:46:20 -04:00
static void update_events(void);
2011-11-12 23:47:16 -04:00
////////////////////////////////////////////////////////////////////////////////
// Dataflash
////////////////////////////////////////////////////////////////////////////////
2012-12-12 19:46:20 -04:00
#if CONFIG_HAL_BOARD == HAL_BOARD_APM2
DataFlash_APM2 DataFlash;
2012-12-13 22:16:32 -04:00
#elif CONFIG_HAL_BOARD == HAL_BOARD_APM1
2012-12-12 19:46:20 -04:00
DataFlash_APM1 DataFlash;
2012-12-13 22:16:32 -04:00
#elif CONFIG_HAL_BOARD == HAL_BOARD_AVR_SITL
DataFlash_SITL DataFlash;
2013-01-02 07:08:40 -04:00
#else
DataFlash_Empty DataFlash;
2011-11-12 23:47:16 -04:00
#endif
2011-05-09 14:40:32 -03:00
2012-11-29 07:56:54 -04:00
////////////////////////////////////////////////////////////////////////////////
// the rate we run the main loop at
////////////////////////////////////////////////////////////////////////////////
2012-12-09 01:27:33 -04:00
static const AP_InertialSensor::Sample_rate ins_sample_rate = AP_InertialSensor::RATE_200HZ;
2012-11-29 07:56:54 -04:00
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// Sensors
////////////////////////////////////////////////////////////////////////////////
//
// There are three basic options related to flight sensor selection.
//
2012-11-10 01:29:56 -04:00
// - Normal flight mode. Real sensors are used.
// - HIL Attitude mode. Most sensors are disabled, as the HIL
2011-02-17 03:09:13 -04:00
// protocol supplies attitude information directly.
2012-11-10 01:29:56 -04:00
// - HIL Sensors mode. Synthetic sensors are configured that
2011-02-17 03:09:13 -04:00
// supply data from the simulation.
//
2011-02-19 03:44:44 -04:00
// All GPS access should be through this pointer.
2011-07-17 07:31:46 -03:00
static GPS *g_gps;
2011-02-17 03:09:13 -04:00
2011-07-17 07:30:53 -03:00
// flight modes convenience array
2012-12-12 19:46:20 -04:00
static AP_Int8 *flight_modes = &g.flight_mode1;
2011-07-17 07:30:53 -03:00
2011-05-09 09:20:22 -03:00
#if HIL_MODE == HIL_MODE_DISABLED
2011-02-24 01:56:59 -04:00
2012-08-21 23:19:50 -03:00
#if CONFIG_ADC == ENABLED
AP_ADC_ADS7844 adc;
#endif
2012-12-14 15:02:09 -04:00
#if CONFIG_IMU_TYPE == CONFIG_IMU_MPU6000
AP_InertialSensor_MPU6000 ins;
2012-12-18 06:15:11 -04:00
#elif CONFIG_IMU_TYPE == CONFIG_IMU_OILPAN
2012-12-14 15:02:09 -04:00
AP_InertialSensor_Oilpan ins(&adc);
2012-12-18 06:15:11 -04:00
#elif CONFIG_IMU_TYPE == CONFIG_IMU_SITL
AP_InertialSensor_Stub ins;
2013-01-05 05:38:19 -04:00
#elif CONFIG_IMU_TYPE == CONFIG_IMU_PX4
AP_InertialSensor_PX4 ins;
2012-12-14 15:02:09 -04:00
#endif
#if CONFIG_HAL_BOARD == HAL_BOARD_AVR_SITL
// When building for SITL we use the HIL barometer and compass drivers
2012-08-21 23:19:50 -03:00
AP_Baro_BMP085_HIL barometer;
AP_Compass_HIL compass;
2012-12-18 06:15:11 -04:00
SITL sitl;
2012-08-21 23:19:50 -03:00
#else
2012-12-14 15:02:09 -04:00
// Otherwise, instantiate a real barometer and compass driver
2012-08-21 23:19:50 -03:00
#if CONFIG_BARO == AP_BARO_BMP085
2012-12-14 15:02:09 -04:00
AP_Baro_BMP085 barometer;
2013-01-05 05:38:19 -04:00
#elif CONFIG_BARO == AP_BARO_PX4
AP_Baro_PX4 barometer;
2012-08-21 23:19:50 -03:00
#elif CONFIG_BARO == AP_BARO_MS5611
2013-01-08 14:25:51 -04:00
#if CONFIG_MS5611_SERIAL == AP_BARO_MS5611_SPI
2013-01-03 14:21:17 -04:00
AP_Baro_MS5611 barometer(&AP_Baro_MS5611::spi);
2013-01-08 14:25:51 -04:00
#elif CONFIG_MS5611_SERIAL == AP_BARO_MS5611_I2C
2013-01-03 14:21:17 -04:00
AP_Baro_MS5611 barometer(&AP_Baro_MS5611::i2c);
#else
#error Unrecognized CONFIG_MS5611_SERIAL setting.
#endif
2012-08-21 23:19:50 -03:00
#endif
2013-01-05 05:38:19 -04:00
#if CONFIG_HAL_BOARD == HAL_BOARD_PX4
AP_Compass_PX4 compass;
#else
2012-08-21 23:19:50 -03:00
AP_Compass_HMC5843 compass;
#endif
2013-01-05 05:38:19 -04:00
#endif
2012-08-21 23:19:50 -03:00
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2012-12-14 15:02:09 -04:00
AP_OpticalFlow_ADNS3080 optflow;
2012-08-21 23:19:50 -03:00
#else
AP_OpticalFlow optflow;
#endif
2011-02-25 01:33:39 -04:00
2011-12-03 19:29:23 -04:00
// real GPS selection
2012-08-21 23:19:50 -03:00
#if GPS_PROTOCOL == GPS_PROTOCOL_AUTO
2012-12-17 22:36:57 -04:00
AP_GPS_Auto g_gps_driver(&g_gps);
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_NMEA
2012-12-17 22:36:57 -04:00
AP_GPS_NMEA g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_SIRF
2012-12-17 22:36:57 -04:00
AP_GPS_SIRF g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_UBLOX
2012-12-17 22:36:57 -04:00
AP_GPS_UBLOX g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_MTK
2012-12-17 22:36:57 -04:00
AP_GPS_MTK g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-12-21 15:19:32 -04:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_MTK19
AP_GPS_MTK19 g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#elif GPS_PROTOCOL == GPS_PROTOCOL_NONE
2012-12-17 22:36:57 -04:00
AP_GPS_None g_gps_driver();
2011-02-25 01:33:39 -04:00
2012-08-21 23:19:50 -03:00
#else
#error Unrecognised GPS_PROTOCOL setting.
#endif // GPS PROTOCOL
2011-02-19 03:21:42 -04:00
2012-12-12 19:46:20 -04:00
#if DMP_ENABLED == ENABLED && CONFIG_HAL_BOARD == HAL_BOARD_APM2
2012-11-05 00:32:38 -04:00
AP_AHRS_MPU6000 ahrs(&ins, g_gps); // only works with APM2
2012-08-21 23:19:50 -03:00
#else
2012-11-05 00:32:38 -04:00
AP_AHRS_DCM ahrs(&ins, g_gps);
2012-08-21 23:19:50 -03:00
#endif
2012-03-03 03:35:39 -04:00
2012-09-29 12:25:40 -03:00
// ahrs2 object is the secondary ahrs to allow running DMP in parallel with DCM
2012-12-12 19:46:20 -04:00
#if SECONDARY_DMP_ENABLED == ENABLED && CONFIG_HAL_BOARD == HAL_BOARD_APM2
2012-11-05 00:32:38 -04:00
AP_AHRS_MPU6000 ahrs2(&ins, g_gps); // only works with APM2
2012-09-29 12:25:40 -03:00
#endif
2011-02-24 01:56:59 -04:00
#elif HIL_MODE == HIL_MODE_SENSORS
2012-08-21 23:19:50 -03:00
// sensor emulators
2012-11-10 01:29:56 -04:00
AP_ADC_HIL adc;
AP_Baro_BMP085_HIL barometer;
AP_Compass_HIL compass;
2012-12-18 20:32:49 -04:00
AP_GPS_HIL g_gps_driver;
2012-11-10 01:29:56 -04:00
AP_InertialSensor_Stub ins;
AP_AHRS_DCM ahrs(&ins, g_gps);
2012-11-05 00:32:38 -04:00
2012-08-21 23:19:50 -03:00
static int32_t gps_base_alt;
2011-02-24 01:56:59 -04:00
#elif HIL_MODE == HIL_MODE_ATTITUDE
2012-11-10 01:29:56 -04:00
AP_ADC_HIL adc;
AP_InertialSensor_Stub ins;
2012-11-05 00:32:38 -04:00
AP_AHRS_HIL ahrs(&ins, g_gps);
2012-12-18 20:32:49 -04:00
AP_GPS_HIL g_gps_driver;
2012-11-10 01:29:56 -04:00
AP_Compass_HIL compass; // never used
AP_Baro_BMP085_HIL barometer;
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2012-12-12 19:46:20 -04:00
#if CONFIG_HAL_BOARD == HAL_BOARD_APM2
2012-12-14 15:02:09 -04:00
AP_OpticalFlow_ADNS3080 optflow;
2012-11-18 12:16:07 -04:00
#else
2012-12-14 15:02:09 -04:00
AP_OpticalFlow_ADNS3080 optflow;
2012-12-12 19:46:20 -04:00
#endif // CONFIG_HAL_BOARD == HAL_BOARD_APM2
2012-11-18 12:16:07 -04:00
#endif // OPTFLOW == ENABLED
2012-08-21 23:19:50 -03:00
static int32_t gps_base_alt;
2011-02-24 01:56:59 -04:00
#else
2012-08-21 23:19:50 -03:00
#error Unrecognised HIL_MODE setting.
2011-02-24 01:56:59 -04:00
#endif // HIL MODE
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// GCS selection
////////////////////////////////////////////////////////////////////////////////
2012-08-21 23:19:50 -03:00
GCS_MAVLINK gcs0;
GCS_MAVLINK gcs3;
2011-03-26 03:35:52 -03:00
2011-06-16 14:03:26 -03:00
////////////////////////////////////////////////////////////////////////////////
// SONAR selection
////////////////////////////////////////////////////////////////////////////////
//
2013-01-08 03:41:07 -04:00
ModeFilterInt16_Size3 sonar_mode_filter(1);
2011-11-12 23:47:16 -04:00
#if CONFIG_SONAR == ENABLED
2012-12-12 19:53:48 -04:00
AP_HAL::AnalogSource *sonar_analog_source;
AP_RangeFinder_MaxsonarXL *sonar;
2011-11-12 23:47:16 -04:00
#endif
2011-02-20 19:09:28 -04:00
2011-10-15 19:29:33 -03:00
////////////////////////////////////////////////////////////////////////////////
// User variables
////////////////////////////////////////////////////////////////////////////////
#ifdef USERHOOK_VARIABLES
2012-08-21 23:19:50 -03:00
#include USERHOOK_VARIABLES
2011-10-15 19:29:33 -03:00
#endif
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////
2010-12-19 12:40:33 -04:00
/* Radio values
2012-08-21 23:19:50 -03:00
* Channel assignments
* 1 Ailerons (rudder if no ailerons)
* 2 Elevator
* 3 Throttle
* 4 Rudder (if we have ailerons)
* 5 Mode - 3 position switch
* 6 User assignable
* 7 trainer switch - sets throttle nominal (toggle switch), sets accels to Level (hold > 1 second)
* 8 TBD
* Each Aux channel can be configured to have any of the available auxiliary functions assigned to it.
* See libraries/RC_Channel/RC_Channel_aux.h for more information
*/
2010-12-19 12:40:33 -04:00
2012-01-04 02:54:29 -04:00
//Documentation of GLobals:
2012-11-10 01:39:41 -04:00
static union {
struct {
uint8_t home_is_set : 1; // 1
uint8_t simple_mode : 1; // 2 // This is the state of simple mode
uint8_t manual_attitude : 1; // 3
uint8_t manual_throttle : 1; // 4
uint8_t low_battery : 1; // 5 // Used to track if the battery is low - LED output flashes when the batt is low
2013-02-18 01:58:24 -04:00
uint8_t armed : 1; // 6
uint8_t auto_armed : 1; // 7
uint8_t failsafe : 1; // 8 // A status flag for the failsafe state
uint8_t do_flip : 1; // 9 // Used to enable flip code
uint8_t takeoff_complete : 1; // 10
uint8_t land_complete : 1; // 11
uint8_t compass_status : 1; // 12
uint8_t gps_status : 1; // 13
2012-11-10 01:39:41 -04:00
};
uint16_t value;
} ap;
static struct AP_System{
uint8_t GPS_light : 1; // 1 // Solid indicates we have full 3D lock and can navigate, flash = read
uint8_t motor_light : 1; // 2 // Solid indicates Armed state
uint8_t new_radio_frame : 1; // 3 // Set true if we have new PWM data to act on from the Radio
uint8_t nav_ok : 1; // 4 // deprecated
uint8_t CH7_flag : 1; // 5 // manages state of the ch7 toggle switch
2012-11-11 09:42:10 -04:00
uint8_t usb_connected : 1; // 6 // true if APM is powered from USB connection
2013-01-08 01:45:12 -04:00
uint8_t alt_sensor_flag : 1; // 7 // used to track when to read sensors vs estimate alt
uint8_t yaw_stopped : 1; // 8 // Used to manage the Yaw hold capabilities
2012-11-10 01:39:41 -04:00
2012-11-11 09:42:10 -04:00
} ap_system;
2012-11-10 01:39:41 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2010-12-19 12:40:33 -04:00
// Radio
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// This is the state of the flight control system
// There are multiple states defined such as STABILIZE, ACRO,
2012-11-10 01:39:41 -04:00
static int8_t control_mode = STABILIZE;
2012-01-04 02:54:29 -04:00
// Used to maintain the state of the previous control switch position
// This is set to -1 when we need to re-read the switch
2012-12-12 19:46:20 -04:00
static uint8_t oldSwitchPosition;
2012-01-04 02:54:29 -04:00
2012-11-22 05:59:33 -04:00
// receiver RSSI
static uint8_t receiver_rssi;
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Motor Output
////////////////////////////////////////////////////////////////////////////////
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == QUAD_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsQuad
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == TRI_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsTri
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == HEXA_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsHexa
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == Y6_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsY6
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == OCTA_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsOcta
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == OCTA_QUAD_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsOctaQuad
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == HELI_FRAME
2012-08-21 23:19:50 -03:00
#define MOTOR_CLASS AP_MotorsHeli
2012-04-04 10:50:43 -03:00
#endif
2012-11-10 01:29:56 -04:00
#if FRAME_CONFIG == HELI_FRAME // helicopter constructor requires more arguments
2013-01-02 00:28:34 -04:00
MOTOR_CLASS motors(&g.rc_1, &g.rc_2, &g.rc_3, &g.rc_4, &g.rc_8, &g.heli_servo_1, &g.heli_servo_2, &g.heli_servo_3, &g.heli_servo_4);
2012-05-13 00:36:46 -03:00
#elif FRAME_CONFIG == TRI_FRAME // tri constructor requires additional rc_7 argument to allow tail servo reversing
2013-01-02 00:28:34 -04:00
MOTOR_CLASS motors(&g.rc_1, &g.rc_2, &g.rc_3, &g.rc_4, &g.rc_7);
2012-04-04 10:50:43 -03:00
#else
2013-01-02 00:28:34 -04:00
MOTOR_CLASS motors(&g.rc_1, &g.rc_2, &g.rc_3, &g.rc_4);
2012-04-04 10:50:43 -03:00
#endif
2011-11-20 04:21:19 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2011-02-17 03:09:13 -04:00
// PIDs
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// This is a convienience accessor for the IMU roll rates. It's currently the raw IMU rates
// and not the adjusted omega rates, but the name is stuck
2011-07-17 07:31:46 -03:00
static Vector3f omega;
2012-01-04 02:54:29 -04:00
// This is used to hold radio tuning values for in-flight CH6 tuning
2011-09-10 19:16:51 -03:00
float tuning_value;
2013-01-08 01:45:12 -04:00
// used to limit the rate that the pid controller output is logged so that it doesn't negatively affect performance
static uint8_t pid_log_counter;
2010-12-19 12:40:33 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2011-02-17 03:09:13 -04:00
// LED output
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// This is current status for the LED lights state machine
// setting this value changes the output of the LEDs
2012-12-12 19:46:20 -04:00
static uint8_t led_mode = NORMAL_LEDS;
2012-04-12 10:54:14 -03:00
// Blinking indicates GPS status
2012-12-12 19:46:20 -04:00
static uint8_t copter_leds_GPS_blink;
2012-04-12 10:54:14 -03:00
// Blinking indicates battery status
2012-12-12 19:46:20 -04:00
static uint8_t copter_leds_motor_blink;
2012-05-22 10:57:38 -03:00
// Navigation confirmation blinks
2012-11-10 01:39:41 -04:00
static int8_t copter_leds_nav_blink;
2011-01-22 22:36:22 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2010-12-19 12:40:33 -04:00
// GPS variables
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// This is used to scale GPS values for EEPROM storage
// 10^7 times Decimal GPS means 1 == 1cm
// This approximation makes calculations integer and it's easy to read
2012-11-10 01:29:56 -04:00
static const float t7 = 10000000.0;
2012-01-04 02:54:29 -04:00
// We use atan2 and other trig techniques to calaculate angles
// We need to scale the longitude up to make these calcs work
2012-01-15 19:11:02 -04:00
// to account for decreasing distance between lines of longitude away from the equator
2012-11-10 01:29:56 -04:00
static float scaleLongUp = 1;
2012-01-04 02:54:29 -04:00
// Sometimes we need to remove the scaling for distance calcs
2012-11-10 01:29:56 -04:00
static float scaleLongDown = 1;
2011-02-17 03:09:13 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Mavlink specific
////////////////////////////////////////////////////////////////////////////////
// Used by Mavlink for unknow reasons
2012-11-10 01:29:56 -04:00
static const float radius_of_earth = 6378100; // meters
2011-09-04 21:15:36 -03:00
2012-04-21 19:17:09 -03:00
// Unions for getting byte values
2012-08-21 23:19:50 -03:00
union float_int {
int32_t int_value;
float float_value;
2012-04-21 19:17:09 -03:00
} float_int;
2011-07-17 07:31:46 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Location & Navigation
////////////////////////////////////////////////////////////////////////////////
// This is the angle from the copter to the "next_WP" location in degrees * 100
2012-12-08 01:23:32 -04:00
static int32_t wp_bearing;
2013-01-24 00:36:55 -04:00
// navigation mode - options include NAV_NONE, NAV_LOITER, NAV_CIRCLE, NAV_WP
static uint8_t nav_mode;
2012-01-04 02:54:29 -04:00
// Register containing the index of the current navigation command in the mission script
2012-08-21 23:19:50 -03:00
static int16_t command_nav_index;
2012-01-04 02:54:29 -04:00
// Register containing the index of the previous navigation command in the mission script
// Used to manage the execution of conditional commands
2012-08-21 23:19:50 -03:00
static uint8_t prev_nav_index;
2012-01-04 02:54:29 -04:00
// Register containing the index of the current conditional command in the mission script
2012-08-21 23:19:50 -03:00
static uint8_t command_cond_index;
2012-01-04 02:54:29 -04:00
// Used to track the required WP navigation information
// options include
// NAV_ALTITUDE - have we reached the desired altitude?
// NAV_LOCATION - have we reached the desired location?
2012-08-21 23:19:50 -03:00
// NAV_DELAY - have we waited at the waypoint the desired time?
static uint8_t wp_verify_byte; // used for tracking state of navigating waypoints
2013-02-18 01:58:24 -04:00
static float lon_error, lat_error; // Used to report how many cm we are from the next waypoint or loiter target position
2012-08-16 19:39:50 -03:00
static int16_t control_roll;
static int16_t control_pitch;
2012-11-29 08:08:19 -04:00
static uint8_t rtl_state;
2012-08-16 19:39:50 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Orientation
////////////////////////////////////////////////////////////////////////////////
// Convienience accessors for commonly used trig functions. These values are generated
// by the DCM through a few simple equations. They are used throughout the code where cos and sin
// would normally be used.
// The cos values are defaulted to 1 to get a decent initial value for a level state
2012-08-21 23:19:50 -03:00
static float cos_roll_x = 1;
static float cos_pitch_x = 1;
static float cos_yaw_x = 1;
2013-01-22 05:17:19 -04:00
static float sin_yaw_y = 1;
static float cos_yaw = 1;
static float sin_yaw = 1;
static float sin_roll = 1;
static float sin_pitch = 1;
2011-09-04 21:15:36 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// SIMPLE Mode
////////////////////////////////////////////////////////////////////////////////
// Used to track the orientation of the copter for Simple mode. This value is reset at each arming
// or in SuperSimple mode when the copter leaves a 20m radius from home.
static int32_t initial_simple_bearing;
2012-10-01 02:02:49 -03:00
////////////////////////////////////////////////////////////////////////////////
// Rate contoller targets
////////////////////////////////////////////////////////////////////////////////
2012-10-14 05:47:46 -03:00
static uint8_t rate_targets_frame = EARTH_FRAME; // indicates whether rate targets provided in earth or body frame
2013-02-22 02:23:03 -04:00
static int32_t roll_rate_target_ef;
static int32_t pitch_rate_target_ef;
static int32_t yaw_rate_target_ef;
static int32_t roll_rate_target_bf; // body frame roll rate target
static int32_t pitch_rate_target_bf; // body frame pitch rate target
static int32_t yaw_rate_target_bf; // body frame yaw rate target
2012-10-01 02:02:49 -03:00
2012-11-23 02:57:49 -04:00
////////////////////////////////////////////////////////////////////////////////
// Throttle variables
////////////////////////////////////////////////////////////////////////////////
2012-12-03 10:05:14 -04:00
static int16_t throttle_accel_target_ef; // earth frame throttle acceleration target
static bool throttle_accel_controller_active; // true when accel based throttle controller is active, false when higher level throttle controllers are providing throttle output directly
2012-11-23 02:57:49 -04:00
static float throttle_avg; // g.throttle_cruise as a float
2012-11-24 03:45:28 -04:00
static int16_t desired_climb_rate; // pilot desired climb rate - for logging purposes only
2012-11-23 02:57:49 -04:00
2012-02-19 01:16:19 -04:00
////////////////////////////////////////////////////////////////////////////////
// ACRO Mode
////////////////////////////////////////////////////////////////////////////////
// Used to control Axis lock
int32_t roll_axis;
int32_t pitch_axis;
2012-03-09 03:13:04 -04:00
2012-02-28 09:56:26 -04:00
// Filters
2012-08-21 23:19:50 -03:00
AP_LeadFilter xLeadFilter; // Long GPS lag filter
AP_LeadFilter yLeadFilter; // Lat GPS lag filter
2012-11-26 22:21:12 -04:00
#if FRAME_CONFIG == HELI_FRAME
2012-11-26 22:50:39 -04:00
LowPassFilterFloat rate_roll_filter; // Rate Roll filter
2012-12-04 15:42:04 -04:00
LowPassFilterFloat rate_pitch_filter; // Rate Pitch filter
// LowPassFilterFloat rate_yaw_filter; // Rate Yaw filter
2012-11-26 22:21:12 -04:00
#endif // HELI_FRAME
2012-06-26 02:31:27 -03:00
2012-03-09 03:13:04 -04:00
// Barometer filter
2012-11-10 01:37:16 -04:00
AverageFilterInt32_Size5 baro_filter;
2012-03-09 03:13:04 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Circle Mode / Loiter control
////////////////////////////////////////////////////////////////////////////////
2013-02-25 04:50:56 -04:00
// used to control the speed of Circle mode in radians/second, default is 5° per second
2011-11-13 17:40:31 -04:00
static const float circle_rate = 0.0872664625;
2013-02-25 04:50:56 -04:00
Vector2f circle_center; // circle position expressed in cm from home location. x = lat, y = lon
// angle from the circle center to the copter's desired location. Incremented at circle_rate / second
static float circle_angle;
// the total angle (in radians) travelled
static float circle_angle_total;
// deg : how many times to circle as specified by mission command
static uint8_t circle_desired_rotations;
2012-01-04 02:54:29 -04:00
// How long we should stay in Loiter Mode for mission scripting
static uint16_t loiter_time_max;
// How long have we been loitering - The start time in millis
static uint32_t loiter_time;
// The synthetic location created to make the copter do circles around a WP
2012-08-21 23:19:50 -03:00
static struct Location circle_WP;
2013-01-25 02:11:09 -04:00
// inertial nav loiter variables
2013-02-18 01:58:24 -04:00
static float loiter_lat_from_home_cm; // loiter's target latitude in cm from home
static float loiter_lon_from_home_cm; // loiter's target longitude in cm from home
2011-11-13 01:43:21 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// CH7 control
////////////////////////////////////////////////////////////////////////////////
// This register tracks the current Mission Command index when writing
// a mission using CH7 in flight
2011-11-13 01:43:21 -04:00
static int8_t CH7_wp_index;
2011-10-29 01:29:10 -03:00
2011-07-10 21:47:08 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2011-02-25 01:33:39 -04:00
// Battery Sensors
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-01-15 20:10:02 -04:00
// Battery Voltage of battery, initialized above threshold for filter
2013-01-10 14:42:24 -04:00
static float battery_voltage1 = LOW_VOLTAGE * 1.05f;
2012-01-04 02:54:29 -04:00
// refers to the instant amp draw – based on an Attopilot Current sensor
2012-08-21 23:19:50 -03:00
static float current_amps1;
2012-01-04 02:54:29 -04:00
// refers to the total amps drawn – based on an Attopilot Current sensor
2012-08-21 23:19:50 -03:00
static float current_total1;
2010-12-19 12:40:33 -04:00
2011-11-05 01:41:51 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Altitude
////////////////////////////////////////////////////////////////////////////////
2013-01-08 03:41:07 -04:00
// The (throttle) controller desired altitude in cm
static float controller_desired_alt;
2012-02-01 00:39:15 -04:00
// The cm we are off in altitude from next_WP.alt – Positive value means we are below the WP
2012-08-21 23:19:50 -03:00
static int32_t altitude_error;
2012-03-07 02:22:14 -04:00
// The cm/s we are moving up or down based on filtered data - Positive = UP
2012-08-21 23:19:50 -03:00
static int16_t climb_rate;
2012-01-04 02:54:29 -04:00
// The altitude as reported by Sonar in cm – Values are 20 to 700 generally.
2012-08-21 23:19:50 -03:00
static int16_t sonar_alt;
2013-01-08 03:41:07 -04:00
static uint8_t sonar_alt_health; // true if we can trust the altitude from the sonar
2012-01-04 02:54:29 -04:00
// The altitude as reported by Baro in cm – Values can be quite high
2012-08-21 23:19:50 -03:00
static int32_t baro_alt;
2012-11-10 01:39:41 -04:00
2012-08-21 23:19:50 -03:00
static int16_t saved_toy_throttle;
2011-11-05 01:41:51 -03:00
2012-01-29 02:00:05 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// flight modes
////////////////////////////////////////////////////////////////////////////////
// Flight modes are combinations of Roll/Pitch, Yaw and Throttle control modes
// Each Flight mode is a unique combination of these modes
//
// The current desired control scheme for Yaw
2012-12-08 01:23:32 -04:00
static uint8_t yaw_mode;
2012-01-04 02:54:29 -04:00
// The current desired control scheme for roll and pitch / navigation
2012-12-08 01:23:32 -04:00
static uint8_t roll_pitch_mode;
2012-01-04 02:54:29 -04:00
// The current desired control scheme for altitude hold
2012-12-08 01:23:32 -04:00
static uint8_t throttle_mode;
2011-09-04 21:15:36 -03:00
2011-12-30 01:35:01 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// flight specific
////////////////////////////////////////////////////////////////////////////////
// An additional throttle added to keep the copter at the same altitude when banking
2012-08-21 23:19:50 -03:00
static int16_t angle_boost;
2012-11-24 09:50:09 -04:00
// counter to verify landings
static uint16_t land_detector;
2012-01-29 02:00:05 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Navigation general
////////////////////////////////////////////////////////////////////////////////
2012-12-08 01:23:32 -04:00
// The location of home in relation to the copter, updated every GPS read
static int32_t home_bearing;
2012-01-22 02:04:35 -04:00
// distance between plane and home in cm
2012-08-21 23:19:50 -03:00
static int32_t home_distance;
2012-01-22 02:04:35 -04:00
// distance between plane and next_WP in cm
2012-07-10 19:39:13 -03:00
// is not static because AP_Camera uses it
2013-01-26 04:04:12 -04:00
uint32_t wp_distance;
2013-01-27 10:48:07 -04:00
// wpinav variables
Vector2f wpinav_origin; // starting point of trip to next waypoint in cm from home (equivalent to next_WP)
Vector2f wpinav_destination; // target destination in cm from home (equivalent to next_WP)
Vector2f wpinav_target; // the intermediate target location in cm from home
Vector2f wpinav_pos_delta; // position difference between origin and destination
float wpinav_track_length; // distance in cm between origin and destination
float wpinav_track_desired; // the desired distance along the track in cm
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// 3D Location vectors
////////////////////////////////////////////////////////////////////////////////
// home location is stored when we have a good GPS lock and arm the copter
// Can be reset each the copter is re-armed
2012-08-21 23:19:50 -03:00
static struct Location home;
2012-01-04 02:54:29 -04:00
// Current location of the copter
2012-08-21 23:19:50 -03:00
static struct Location current_loc;
2012-01-04 02:54:29 -04:00
// Next WP is the desired location of the copter - the next waypoint or loiter location
2012-08-21 23:19:50 -03:00
static struct Location next_WP;
2012-01-04 02:54:29 -04:00
// Prev WP is used to get the optimum path from one WP to the next
2012-08-21 23:19:50 -03:00
static struct Location prev_WP;
2012-01-04 02:54:29 -04:00
// Holds the current loaded command from the EEPROM for navigation
2012-08-21 23:19:50 -03:00
static struct Location command_nav_queue;
2012-01-04 02:54:29 -04:00
// Holds the current loaded command from the EEPROM for conditional scripts
2012-08-21 23:19:50 -03:00
static struct Location command_cond_queue;
2012-01-04 02:54:29 -04:00
// Holds the current loaded command from the EEPROM for guided mode
static struct Location guided_WP;
2012-08-09 20:44:21 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Crosstrack
////////////////////////////////////////////////////////////////////////////////
// deg * 100, The original angle to the next_WP when the next_WP was set
// Also used to check when we pass a WP
2012-12-08 01:23:32 -04:00
static int32_t original_wp_bearing;
// The amount of angle correction applied to wp_bearing to bring the copter back on its optimum path
2012-08-21 23:19:50 -03:00
static int16_t crosstrack_error;
2011-11-07 18:24:32 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Navigation Roll/Pitch functions
////////////////////////////////////////////////////////////////////////////////
// all angles are deg * 100 : target yaw angle
// The Commanded ROll from the autopilot.
2012-08-21 23:19:50 -03:00
static int32_t nav_roll;
2012-01-04 02:54:29 -04:00
// The Commanded pitch from the autopilot. negative Pitch means go forward.
2012-08-21 23:19:50 -03:00
static int32_t nav_pitch;
2012-01-04 02:54:29 -04:00
// The desired bank towards North (Positive) or South (Negative)
2012-08-21 23:19:50 -03:00
static int32_t auto_roll;
static int32_t auto_pitch;
2012-02-15 13:09:52 -04:00
2012-01-04 02:54:29 -04:00
// Don't be fooled by the fact that Pitch is reversed from Roll in its sign!
2012-08-21 23:19:50 -03:00
static int16_t nav_lat;
2012-01-04 02:54:29 -04:00
// The desired bank towards East (Positive) or West (Negative)
2012-08-21 23:19:50 -03:00
static int16_t nav_lon;
2012-01-09 00:53:54 -04:00
// The Commanded ROll from the autopilot based on optical flow sensor.
2012-08-21 23:19:50 -03:00
static int32_t of_roll;
2012-01-09 00:53:54 -04:00
// The Commanded pitch from the autopilot based on optical flow sensor. negative Pitch means go forward.
2012-08-21 23:19:50 -03:00
static int32_t of_pitch;
2012-01-09 00:53:54 -04:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Navigation Throttle control
////////////////////////////////////////////////////////////////////////////////
// The Commanded Throttle from the autopilot.
2012-11-10 01:39:41 -04:00
static int16_t nav_throttle; // 0-1000 for throttle control
2012-01-04 02:54:29 -04:00
// This is a simple counter to track the amount of throttle used during flight
// This could be useful later in determining and debuging current usage and predicting battery life
static uint32_t throttle_integrator;
2011-07-17 07:31:46 -03:00
2012-01-11 03:31:38 -04:00
////////////////////////////////////////////////////////////////////////////////
// Climb rate control
////////////////////////////////////////////////////////////////////////////////
// Time when we intiated command in millis - used for controlling decent rate
// Used to track the altitude offset for climbrate control
2012-08-21 23:19:50 -03:00
static int8_t alt_change_flag;
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Navigation Yaw control
////////////////////////////////////////////////////////////////////////////////
// The Commanded Yaw from the autopilot.
2012-08-21 23:19:50 -03:00
static int32_t nav_yaw;
2012-07-01 17:38:53 -03:00
static uint8_t yaw_timer;
2012-12-08 01:23:32 -04:00
// Yaw will point at this location if yaw_mode is set to YAW_LOOK_AT_LOCATION
static struct Location yaw_look_at_WP;
// bearing from current location to the yaw_look_at_WP
static int32_t yaw_look_at_WP_bearing;
// yaw used for YAW_LOOK_AT_HEADING yaw_mode
static int32_t yaw_look_at_heading;
2012-01-04 02:54:29 -04:00
// Deg/s we should turn
2012-12-08 01:23:32 -04:00
static int16_t yaw_look_at_heading_slew;
2011-07-17 07:31:46 -03:00
2011-06-16 14:03:26 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Repeat Mission Scripting Command
////////////////////////////////////////////////////////////////////////////////
// The type of repeating event - Toggle a servo channel, Toggle the APM1 relay, etc
2012-12-12 19:46:20 -04:00
static uint8_t event_id;
2012-01-04 02:54:29 -04:00
// Used to manage the timimng of repeating events
static uint32_t event_timer;
// How long to delay the next firing of event in millis
static uint16_t event_delay;
// how many times to fire : 0 = forever, 1 = do once, 2 = do twice
2012-08-21 23:19:50 -03:00
static int16_t event_repeat;
2012-01-04 02:54:29 -04:00
// per command value, such as PWM for servos
2012-08-21 23:19:50 -03:00
static int16_t event_value;
2012-01-04 02:54:29 -04:00
// the stored value used to undo commands - such as original PWM command
2012-08-21 23:19:50 -03:00
static int16_t event_undo_value;
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Delay Mission Scripting Command
////////////////////////////////////////////////////////////////////////////////
2012-08-21 23:19:50 -03:00
static int32_t condition_value; // used in condition commands (eg delay, change alt, etc.)
2012-01-10 00:23:37 -04:00
static uint32_t condition_start;
2010-12-19 12:40:33 -04:00
2011-04-20 02:37:05 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2010-12-19 12:40:33 -04:00
// IMU variables
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// Integration time for the gyros (DCM algorithm)
2012-05-17 14:55:13 -03:00
// Updated with the fast loop
2012-11-10 01:39:41 -04:00
static float G_Dt = 0.02;
2010-12-19 12:40:33 -04:00
2012-06-14 02:27:03 -03:00
////////////////////////////////////////////////////////////////////////////////
// Inertial Navigation
////////////////////////////////////////////////////////////////////////////////
2012-11-10 01:39:41 -04:00
AP_InertialNav inertial_nav(&ahrs, &ins, &barometer, &g_gps);
2012-06-14 02:27:03 -03:00
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
2010-12-19 12:40:33 -04:00
// Performance monitoring
2012-01-04 02:54:29 -04:00
////////////////////////////////////////////////////////////////////////////////
// The number of GPS fixes we have had
2013-01-12 03:15:23 -04:00
static uint8_t gps_fix_count;
2010-12-19 12:40:33 -04:00
// System Timers
// --------------
2012-01-04 02:54:29 -04:00
// Time in microseconds of main control loop
2012-08-21 23:19:50 -03:00
static uint32_t fast_loopTimer;
2012-01-04 02:54:29 -04:00
// Counters for branching from 10 hz control loop
2012-12-12 19:46:20 -04:00
static uint8_t medium_loopCounter;
2012-01-04 02:54:29 -04:00
// Counters for branching from 3 1/3hz control loop
2012-12-12 19:46:20 -04:00
static uint8_t slow_loopCounter;
2012-10-09 00:30:17 -03:00
// Counter of main loop executions. Used for performance monitoring and failsafe processing
static uint16_t mainLoop_count;
2012-01-04 02:54:29 -04:00
// Delta Time in milliseconds for navigation computations, updated with every good GPS read
2012-08-21 23:19:50 -03:00
static float dTnav;
2012-01-04 02:54:29 -04:00
// Counters for branching from 4 minute control loop used to save Compass offsets
2012-08-21 23:19:50 -03:00
static int16_t superslow_loopCounter;
2012-04-16 12:07:57 -03:00
// Loiter timer - Records how long we have been in loiter
2012-11-29 08:08:19 -04:00
static uint32_t rtl_loiter_start_time;
2012-01-20 14:06:46 -04:00
// disarms the copter while in Acro or Stabilize mode after 30 seconds of no flight
2012-08-21 23:19:50 -03:00
static uint8_t auto_disarming_counter;
2012-05-18 13:54:18 -03:00
// prevents duplicate GPS messages from entering system
2012-08-21 23:19:50 -03:00
static uint32_t last_gps_time;
2010-12-19 12:40:33 -04:00
2012-12-19 11:06:20 -04:00
// Used to exit the roll and pitch auto trim function
static uint8_t auto_trim_counter;
2011-03-09 02:37:09 -04:00
2012-12-22 04:26:27 -04:00
// Reference to the relay object (APM1 -> PORTL 2) (APM2 -> PORTB 7)
2011-10-02 09:52:02 -03:00
AP_Relay relay;
2012-12-22 04:26:27 -04:00
//Reference to the camera object (it uses the relay object inside it)
#if CAMERA == ENABLED
AP_Camera camera(&relay);
#endif
2012-12-14 00:12:39 -04:00
// a pin for reading the receiver RSSI voltage. The scaling by 0.25
2012-11-22 05:59:33 -04:00
// is to take the 0 to 1024 range down to an 8 bit range for MAVLink
2012-12-12 20:16:32 -04:00
AP_HAL::AnalogSource* rssi_analog_source;
2012-11-22 05:59:33 -04:00
2012-12-13 15:48:01 -04:00
// Input sources for battery voltage, battery current, board vcc
AP_HAL::AnalogSource* batt_volt_analog_source;
AP_HAL::AnalogSource* batt_curr_analog_source;
AP_HAL::AnalogSource* board_vcc_analog_source;
2012-09-11 00:52:10 -03:00
#if CLI_ENABLED == ENABLED
static int8_t setup_show (uint8_t argc, const Menu::arg *argv);
2012-09-11 01:25:53 -03:00
#endif
2012-01-04 02:54:29 -04:00
2012-07-10 19:39:13 -03:00
// Camera/Antenna mount tracking and stabilisation stuff
// --------------------------------------
#if MOUNT == ENABLED
// current_loc uses the baro/gps soloution for altitude rather than gps only.
// mabe one could use current_loc for lat/lon too and eliminate g_gps alltogether?
2012-08-08 18:11:23 -03:00
AP_Mount camera_mount(¤t_loc, g_gps, &ahrs, 0);
2012-07-10 19:39:13 -03:00
#endif
2012-08-08 17:16:48 -03:00
#if MOUNT2 == ENABLED
// current_loc uses the baro/gps soloution for altitude rather than gps only.
// mabe one could use current_loc for lat/lon too and eliminate g_gps alltogether?
2012-08-08 18:11:23 -03:00
AP_Mount camera_mount2(¤t_loc, g_gps, &ahrs, 1);
2012-08-08 17:16:48 -03:00
#endif
2012-07-10 19:39:13 -03:00
2012-07-14 23:26:17 -03:00
////////////////////////////////////////////////////////////////////////////////
// Experimental AP_Limits library - set constraints, limits, fences, minima, maxima on various parameters
////////////////////////////////////////////////////////////////////////////////
2012-12-13 03:07:34 -04:00
#if AP_LIMITS == ENABLED
2012-11-10 01:29:56 -04:00
AP_Limits limits;
2012-08-21 23:19:50 -03:00
AP_Limit_GPSLock gpslock_limit(g_gps);
AP_Limit_Geofence geofence_limit(FENCE_START_BYTE, FENCE_WP_SIZE, MAX_FENCEPOINTS, g_gps, &home, ¤t_loc);
AP_Limit_Altitude altitude_limit(¤t_loc);
2012-07-14 23:26:17 -03:00
#endif
2012-11-23 02:57:49 -04:00
////////////////////////////////////////////////////////////////////////////////
// function definitions to keep compiler from complaining about undeclared functions
////////////////////////////////////////////////////////////////////////////////
2012-12-21 23:52:49 -04:00
void get_throttle_althold(int32_t target_alt, int16_t min_climb_rate, int16_t max_climb_rate);
2012-11-23 02:57:49 -04:00
2011-02-17 03:09:13 -04:00
////////////////////////////////////////////////////////////////////////////////
// Top-level logic
////////////////////////////////////////////////////////////////////////////////
2010-12-23 10:05:59 -04:00
2012-12-14 17:19:35 -04:00
// setup the var_info table
AP_Param param_loader(var_info, WP_START_BYTE);
2013-01-11 21:01:10 -04:00
/*
scheduler table - all regular tasks apart from the fast_loop()
should be listed here, along with how often they should be called
(in 10ms units) and the maximum time they are expected to take (in
microseconds)
*/
static const AP_Scheduler::Task scheduler_tasks[] PROGMEM = {
{ update_GPS, 2, 900 },
2013-02-18 01:58:24 -04:00
{ update_navigation, 10, 500 },
2013-01-11 21:01:10 -04:00
{ medium_loop, 2, 700 },
2013-02-01 23:00:09 -04:00
{ update_altitude, 5, 1000 },
2013-01-11 21:01:10 -04:00
{ fifty_hz_loop, 2, 950 },
2013-02-18 01:58:24 -04:00
{ run_nav_updates, 10, 800 },
2013-01-11 21:01:10 -04:00
{ slow_loop, 10, 500 },
{ gcs_check_input, 2, 700 },
{ gcs_send_heartbeat, 100, 700 },
{ gcs_data_stream_send, 2, 1500 },
{ gcs_send_deferred, 2, 1200 },
{ compass_accumulate, 2, 700 },
{ barometer_accumulate, 2, 900 },
{ super_slow_loop, 100, 1100 },
{ perf_update, 1000, 500 }
};
2010-12-19 12:40:33 -04:00
void setup() {
2013-01-10 19:24:21 -04:00
// this needs to be the first call, as it fills memory with
// sentinel values
memcheck_init();
2012-12-13 22:16:32 -04:00
cliSerial = hal.console;
// Load the default values of variables listed in var_info[]s
2012-12-14 17:19:35 -04:00
AP_Param::setup_sketch_defaults();
2012-12-12 19:53:48 -04:00
#if CONFIG_SONAR == ENABLED
#if CONFIG_SONAR_SOURCE == SONAR_SOURCE_ADC
2012-12-12 20:16:32 -04:00
sonar_analog_source = new AP_ADC_AnalogSource(
2012-12-12 19:53:48 -04:00
&adc, CONFIG_SONAR_SOURCE_ADC_CHANNEL, 0.25);
#elif CONFIG_SONAR_SOURCE == SONAR_SOURCE_ANALOG_PIN
sonar_analog_source = hal.analogin->channel(
CONFIG_SONAR_SOURCE_ANALOG_PIN);
#else
#warning "Invalid CONFIG_SONAR_SOURCE"
#endif
2012-12-12 20:16:32 -04:00
sonar = new AP_RangeFinder_MaxsonarXL(sonar_analog_source,
2012-12-12 19:53:48 -04:00
&sonar_mode_filter);
#endif
2012-12-13 15:48:01 -04:00
rssi_analog_source = hal.analogin->channel(g.rssi_pin, 0.25);
batt_volt_analog_source = hal.analogin->channel(g.battery_volt_pin);
batt_curr_analog_source = hal.analogin->channel(g.battery_curr_pin);
board_vcc_analog_source = hal.analogin->channel(ANALOG_INPUT_BOARD_VCC);
2012-12-12 20:16:32 -04:00
2012-08-21 23:19:50 -03:00
init_ardupilot();
2013-01-11 21:01:10 -04:00
// initialise the main loop scheduler
scheduler.init(&scheduler_tasks[0], sizeof(scheduler_tasks)/sizeof(scheduler_tasks[0]));
2010-12-19 12:40:33 -04:00
}
2013-01-06 20:02:50 -04:00
/*
2013-01-08 01:45:12 -04:00
if the compass is enabled then try to accumulate a reading
2013-01-06 20:02:50 -04:00
*/
2013-01-08 01:45:12 -04:00
static void compass_accumulate(void)
{
if (g.compass_enabled) {
compass.accumulate();
}
}
2013-01-09 08:08:19 -04:00
/*
try to accumulate a baro reading
*/
static void barometer_accumulate(void)
{
barometer.accumulate();
}
2013-01-08 01:45:12 -04:00
// enable this to get console logging of scheduler performance
#define SCHEDULER_DEBUG 0
static void perf_update(void)
2013-01-06 20:02:50 -04:00
{
2013-01-08 01:45:12 -04:00
if (g.log_bitmask & MASK_LOG_PM)
Log_Write_Performance();
2013-01-11 21:06:40 -04:00
if (scheduler.debug()) {
cliSerial->printf_P(PSTR("PERF: %u/%u %lu\n"),
(unsigned)perf_info_get_num_long_running(),
(unsigned)perf_info_get_num_loops(),
(unsigned long)perf_info_get_max_time());
}
2013-01-08 01:45:12 -04:00
perf_info_reset();
gps_fix_count = 0;
2013-01-06 20:02:50 -04:00
}
2010-12-19 12:40:33 -04:00
void loop()
{
2012-11-10 01:39:41 -04:00
uint32_t timer = micros();
2012-08-21 23:19:50 -03:00
// We want this to execute fast
// ----------------------------
2013-01-08 01:45:12 -04:00
if (ins.num_samples_available() >= 2) {
2013-01-06 20:04:27 -04:00
2012-11-18 12:16:07 -04:00
// check loop time
perf_info_check_loop_time(timer - fast_loopTimer);
2013-01-08 01:45:12 -04:00
G_Dt = (float)(timer - fast_loopTimer) / 1000000.f; // used by PI Loops
fast_loopTimer = timer;
2012-08-21 23:19:50 -03:00
2012-10-09 00:30:17 -03:00
// for mainloop failure monitoring
mainLoop_count++;
2012-08-21 23:19:50 -03:00
// Execute the fast loop
// ---------------------
2012-11-07 06:03:30 -04:00
fast_loop();
2012-08-21 23:19:50 -03:00
2013-01-11 21:01:10 -04:00
// tell the scheduler one tick has passed
scheduler.tick();
2012-08-30 04:53:04 -03:00
} else {
2013-01-08 01:45:12 -04:00
uint16_t dt = timer - fast_loopTimer;
2013-01-11 21:01:10 -04:00
if (dt < 10000) {
uint16_t time_to_next_loop = 10000 - dt;
scheduler.run(time_to_next_loop);
2012-09-08 00:07:16 -03:00
}
2012-08-26 00:45:19 -03:00
}
2010-12-19 12:40:33 -04:00
}
2011-07-10 21:47:08 -03:00
2013-01-08 01:45:12 -04:00
2012-05-17 14:55:13 -03:00
// Main loop - 100hz
2011-07-17 07:31:46 -03:00
static void fast_loop()
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
// IMU DCM Algorithm
// --------------------
read_AHRS();
2011-09-19 18:02:42 -03:00
2012-11-07 06:03:30 -04:00
// reads all of the necessary trig functions for cameras, throttle, etc.
// --------------------------------------------------------------------
update_trig();
2013-02-22 16:56:26 -04:00
// Acrobatic control
if (ap.do_flip) {
if(abs(g.rc_1.control_in) < 4000) {
// calling roll_flip will override the desired roll rate and throttle output
roll_flip();
}else{
// force an exit from the loop if we are not hands off sticks.
ap.do_flip = false;
Log_Write_Event(DATA_EXIT_FLIP);
}
}
2013-01-11 01:32:40 -04:00
// run low level rate controllers that only require IMU data
run_rate_controllers();
// write out the servo PWM values
// ------------------------------
set_servos_4();
2012-08-21 23:19:50 -03:00
// Inertial Nav
// --------------------
2012-11-07 06:03:30 -04:00
read_inertia();
2012-06-14 02:27:03 -03:00
2012-09-14 09:05:20 -03:00
// optical flow
// --------------------
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2012-09-14 09:05:20 -03:00
if(g.optflow_enabled) {
update_optical_flow();
}
2012-11-18 12:16:07 -04:00
#endif // OPTFLOW == ENABLED
2012-09-14 09:05:20 -03:00
2012-11-12 23:50:51 -04:00
// Read radio and 3-position switch on radio
// -----------------------------------------
read_radio();
read_control_switch();
2012-08-21 23:19:50 -03:00
// custom code/exceptions for flight modes
// ---------------------------------------
update_yaw_mode();
update_roll_pitch_mode();
2010-12-19 12:40:33 -04:00
2012-10-01 02:02:49 -03:00
// update targets to rate controllers
update_rate_contoller_targets();
2011-09-27 13:35:05 -03:00
2013-01-08 01:45:12 -04:00
// agmatthews - USERHOOKS
2012-08-21 23:19:50 -03:00
#ifdef USERHOOK_FASTLOOP
USERHOOK_FASTLOOP
#endif
2010-12-19 12:40:33 -04:00
}
2011-07-17 07:31:46 -03:00
static void medium_loop()
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
// This is the start of the medium (10 Hz) loop pieces
// -----------------------------------------
switch(medium_loopCounter) {
// This case deals with the GPS and Compass
//-----------------------------------------
case 0:
medium_loopCounter++;
2013-03-03 10:02:36 -04:00
// read battery before compass because it may be used for motor interference compensation
if (g.battery_monitoring != 0) {
read_battery();
}
2012-08-21 23:19:50 -03:00
#if HIL_MODE != HIL_MODE_ATTITUDE // don't execute in HIL mode
if(g.compass_enabled) {
if (compass.read()) {
compass.null_offsets();
}
}
#endif
2012-12-19 11:06:20 -04:00
// auto_trim - stores roll and pitch radio inputs to ahrs
auto_trim();
2012-08-21 23:19:50 -03:00
// record throttle output
// ------------------------------
throttle_integrator += g.rc_3.servo_out;
break;
// This case performs some navigation computations
//------------------------------------------------
case 1:
medium_loopCounter++;
2012-11-22 05:59:33 -04:00
read_receiver_rssi();
2012-08-21 23:19:50 -03:00
break;
// command processing
//-------------------
case 2:
medium_loopCounter++;
2013-02-09 02:24:02 -04:00
// log compass information
if (motors.armed() && g.log_bitmask & MASK_LOG_COMPASS) {
Log_Write_Compass();
}
2012-08-21 23:19:50 -03:00
if(control_mode == TOY_A) {
update_toy_throttle();
if(throttle_mode == THROTTLE_AUTO) {
update_toy_altitude();
}
}
2012-11-11 09:42:10 -04:00
ap_system.alt_sensor_flag = true;
2012-08-21 23:19:50 -03:00
break;
// This case deals with sending high rate telemetry
//-------------------------------------------------
case 3:
medium_loopCounter++;
// perform next command
// --------------------
if(control_mode == AUTO) {
2012-11-10 01:39:41 -04:00
if(ap.home_is_set && g.command_total > 1) {
2012-08-21 23:19:50 -03:00
update_commands();
}
}
if(motors.armed()) {
2012-09-29 12:25:40 -03:00
if (g.log_bitmask & MASK_LOG_ATTITUDE_MED) {
2012-08-21 23:19:50 -03:00
Log_Write_Attitude();
2012-09-29 12:25:40 -03:00
#if SECONDARY_DMP_ENABLED == ENABLED
Log_Write_DMP();
#endif
}
2012-08-21 23:19:50 -03:00
if (g.log_bitmask & MASK_LOG_MOTORS)
Log_Write_Motors();
}
break;
// This case controls the slow loop
//---------------------------------
case 4:
medium_loopCounter = 0;
// Accel trims = hold > 2 seconds
// Throttle cruise = switch less than 1 second
// --------------------------------------------
read_trim_switch();
// Check for engine arming
// -----------------------
arm_motors();
2013-01-08 01:45:12 -04:00
// agmatthews - USERHOOKS
2012-08-21 23:19:50 -03:00
#ifdef USERHOOK_MEDIUMLOOP
USERHOOK_MEDIUMLOOP
#endif
#if COPTER_LEDS == ENABLED
update_copter_leds();
#endif
break;
default:
// this is just a catch all
// ------------------------
medium_loopCounter = 0;
break;
}
2011-05-09 21:00:05 -03:00
}
2011-04-17 20:08:16 -03:00
2011-05-09 21:00:05 -03:00
// stuff that happens at 50 hz
// ---------------------------
2011-07-17 07:31:46 -03:00
static void fifty_hz_loop()
2011-05-09 21:00:05 -03:00
{
2013-02-01 23:00:09 -04:00
// get altitude and climb rate from inertial lib
read_inertial_altitude();
2012-08-21 23:19:50 -03:00
// Update the throttle ouput
// -------------------------
update_throttle_mode();
#if TOY_EDF == ENABLED
edf_toy();
#endif
2012-08-09 20:44:21 -03:00
2012-08-21 23:19:50 -03:00
#ifdef USERHOOK_50HZLOOP
USERHOOK_50HZLOOP
#endif
2011-08-13 23:30:37 -03:00
2012-05-17 14:55:13 -03:00
2012-08-21 23:19:50 -03:00
#if HIL_MODE != HIL_MODE_DISABLED && FRAME_CONFIG != HELI_FRAME
// HIL for a copter needs very fast update of the servo values
gcs_send_message(MSG_RADIO_OUT);
#endif
2011-07-19 06:49:57 -03:00
2012-07-10 19:39:13 -03:00
#if MOUNT == ENABLED
2012-08-21 23:19:50 -03:00
// update camera mount's position
camera_mount.update_mount_position();
2012-07-10 19:39:13 -03:00
#endif
2012-08-08 17:16:48 -03:00
#if MOUNT2 == ENABLED
2012-08-21 23:19:50 -03:00
// update camera mount's position
camera_mount2.update_mount_position();
2012-08-08 17:16:48 -03:00
#endif
2012-07-10 19:39:13 -03:00
#if CAMERA == ENABLED
2012-12-22 04:26:27 -04:00
camera.trigger_pic_cleanup();
2012-07-10 19:39:13 -03:00
#endif
2011-09-08 01:59:44 -03:00
2012-08-21 23:19:50 -03:00
# if HIL_MODE == HIL_MODE_DISABLED
2012-09-29 12:25:40 -03:00
if (g.log_bitmask & MASK_LOG_ATTITUDE_FAST && motors.armed()) {
2012-08-21 23:19:50 -03:00
Log_Write_Attitude();
2012-09-29 12:25:40 -03:00
#if SECONDARY_DMP_ENABLED == ENABLED
Log_Write_DMP();
#endif
}
2010-12-19 12:40:33 -04:00
2013-01-12 11:17:44 -04:00
if (g.log_bitmask & MASK_LOG_IMU && motors.armed())
Log_Write_IMU();
2012-08-21 23:19:50 -03:00
#endif
2013-01-09 08:08:19 -04:00
2010-12-19 12:40:33 -04:00
}
2011-05-09 21:00:05 -03:00
2011-07-17 07:31:46 -03:00
static void slow_loop()
2010-12-19 12:40:33 -04:00
{
2012-07-14 23:26:17 -03:00
2012-07-16 15:46:43 -03:00
#if AP_LIMITS == ENABLED
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:50 -03:00
// Run the AP_Limits main loop
limits_loop();
2012-07-14 23:26:17 -03:00
#endif // AP_LIMITS_ENABLED
2012-08-21 23:19:50 -03:00
// This is the slow (3 1/3 Hz) loop pieces
//----------------------------------------
switch (slow_loopCounter) {
case 0:
slow_loopCounter++;
superslow_loopCounter++;
2012-11-10 01:39:41 -04:00
// record if the compass is healthy
set_compass_healthy(compass.healthy);
2012-08-21 23:19:50 -03:00
if(superslow_loopCounter > 1200) {
#if HIL_MODE != HIL_MODE_ATTITUDE
if(g.rc_3.control_in == 0 && control_mode == STABILIZE && g.compass_enabled) {
compass.save_offsets();
superslow_loopCounter = 0;
2011-02-24 01:56:59 -04:00
}
2012-08-21 23:19:50 -03:00
#endif
}
2012-04-04 10:50:43 -03:00
2013-02-09 02:24:02 -04:00
if(!motors.armed()) {
2012-09-11 00:26:48 -03:00
// check the user hasn't updated the frame orientation
2012-08-21 23:19:50 -03:00
motors.set_frame_orientation(g.frame_orientation);
}
2012-04-04 10:50:43 -03:00
2012-08-21 23:19:50 -03:00
break;
2011-02-17 05:36:33 -04:00
2012-08-21 23:19:50 -03:00
case 1:
slow_loopCounter++;
2011-02-17 03:09:13 -04:00
2012-08-21 23:19:50 -03:00
#if MOUNT == ENABLED
2012-09-02 00:51:23 -03:00
update_aux_servo_function(&g.rc_5, &g.rc_6, &g.rc_7, &g.rc_8, &g.rc_10, &g.rc_11);
2012-08-21 23:19:50 -03:00
#endif
enable_aux_servos();
2012-07-18 11:49:09 -03:00
2012-08-04 13:44:08 -03:00
#if MOUNT == ENABLED
2012-08-21 23:19:50 -03:00
camera_mount.update_mount_type();
2012-08-04 13:44:08 -03:00
#endif
2012-08-08 17:16:48 -03:00
#if MOUNT2 == ENABLED
2012-08-21 23:19:50 -03:00
camera_mount2.update_mount_type();
2012-08-08 17:16:48 -03:00
#endif
2013-01-08 01:45:12 -04:00
// agmatthews - USERHOOKS
2012-08-21 23:19:50 -03:00
#ifdef USERHOOK_SLOWLOOP
USERHOOK_SLOWLOOP
#endif
2011-06-01 02:50:17 -03:00
2012-08-21 23:19:50 -03:00
break;
2011-02-17 05:36:33 -04:00
2012-08-21 23:19:50 -03:00
case 2:
slow_loopCounter = 0;
update_events();
2011-02-17 05:36:33 -04:00
2012-08-21 23:19:50 -03:00
// blink if we are armed
update_lights();
2011-03-15 02:54:48 -03:00
2012-08-21 23:19:50 -03:00
if(g.radio_tuning > 0)
tuning();
2011-01-18 02:12:11 -04:00
2012-08-21 23:19:50 -03:00
#if USB_MUX_PIN > 0
check_usb_mux();
#endif
break;
2010-12-19 12:40:33 -04:00
2012-08-21 23:19:50 -03:00
default:
slow_loopCounter = 0;
break;
}
2010-12-19 12:40:33 -04:00
}
2012-05-29 16:41:35 -03:00
#define AUTO_DISARMING_DELAY 25
2011-03-09 02:37:09 -04:00
// 1Hz loop
2011-07-17 07:31:46 -03:00
static void super_slow_loop()
2011-02-25 01:33:39 -04:00
{
2013-01-12 11:17:44 -04:00
if (g.log_bitmask != 0) {
Log_Write_Data(DATA_AP_STATE, ap.value);
}
2012-11-11 21:59:53 -04:00
2013-03-03 10:02:36 -04:00
// log battery info to the dataflash
2013-01-26 04:20:41 -04:00
if (g.log_bitmask & MASK_LOG_CURRENT && motors.armed())
2012-08-21 23:19:50 -03:00
Log_Write_Current();
// this function disarms the copter if it has been sitting on the ground for any moment of time greater than 25 seconds
// but only of the control mode is manual
if((control_mode <= ACRO) && (g.rc_3.control_in == 0)) {
auto_disarming_counter++;
if(auto_disarming_counter == AUTO_DISARMING_DELAY) {
init_disarm_motors();
}else if (auto_disarming_counter > AUTO_DISARMING_DELAY) {
auto_disarming_counter = AUTO_DISARMING_DELAY + 1;
}
}else{
auto_disarming_counter = 0;
}
2012-03-07 02:22:14 -04:00
2012-12-20 02:54:19 -04:00
// agmatthews - USERHOOKS
2012-08-21 23:19:50 -03:00
#ifdef USERHOOK_SUPERSLOWLOOP
USERHOOK_SUPERSLOWLOOP
2012-12-14 00:12:39 -04:00
#endif
2011-02-25 01:33:39 -04:00
}
2012-09-14 09:05:20 -03:00
// called at 100hz but data from sensor only arrives at 20 Hz
2012-11-18 12:16:07 -04:00
#if OPTFLOW == ENABLED
2011-12-23 18:20:15 -04:00
static void update_optical_flow(void)
{
2012-09-14 09:05:20 -03:00
static uint32_t last_of_update = 0;
2013-01-08 01:45:12 -04:00
static uint8_t of_log_counter = 0;
2012-01-09 00:53:54 -04:00
2012-09-14 09:05:20 -03:00
// if new data has arrived, process it
if( optflow.last_update != last_of_update ) {
last_of_update = optflow.last_update;
optflow.update_position(ahrs.roll, ahrs.pitch, cos_yaw_x, sin_yaw_y, current_loc.alt); // updates internal lon and lat with estimation based on optical flow
// write to log at 5hz
2013-01-08 01:45:12 -04:00
of_log_counter++;
if( of_log_counter >= 4 ) {
of_log_counter = 0;
2012-09-14 09:05:20 -03:00
if (g.log_bitmask & MASK_LOG_OPTFLOW) {
Log_Write_Optflow();
}
2012-08-21 23:19:50 -03:00
}
}
2011-12-23 18:20:15 -04:00
}
2012-11-18 12:16:07 -04:00
#endif // OPTFLOW == ENABLED
2011-12-23 18:20:15 -04:00
2012-05-21 13:58:14 -03:00
// called at 50hz
2011-07-17 07:31:46 -03:00
static void update_GPS(void)
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
// A counter that is used to grab at least 10 reads before commiting the Home location
2012-12-12 19:46:20 -04:00
static uint8_t ground_start_count = 10;
2012-08-21 23:19:50 -03:00
g_gps->update();
update_GPS_light();
2012-11-10 01:39:41 -04:00
set_gps_healthy(g_gps->status() == g_gps->GPS_OK);
2011-02-19 22:03:01 -04:00
if (g_gps->new_data && g_gps->fix) {
2012-08-21 23:19:50 -03:00
// clear new data flag
g_gps->new_data = false;
// check for duiplicate GPS messages
if(last_gps_time != g_gps->time) {
// for performance monitoring
// --------------------------
gps_fix_count++;
if(ground_start_count > 1) {
ground_start_count--;
} else if (ground_start_count == 1) {
// We countdown N number of good GPS fixes
// so that the altitude is more accurate
// -------------------------------------
2013-01-25 02:11:09 -04:00
if (g_gps->latitude == 0) {
2012-08-21 23:19:50 -03:00
ground_start_count = 5;
}else{
if (g.compass_enabled) {
// Set compass declination automatically
compass.set_initial_location(g_gps->latitude, g_gps->longitude);
}
// save home to eeprom (we must have a good fix to have reached this point)
init_home();
ground_start_count = 0;
}
}
if (g.log_bitmask & MASK_LOG_GPS && motors.armed()) {
Log_Write_GPS();
}
#if HIL_MODE == HIL_MODE_ATTITUDE // only execute in HIL mode
2012-11-11 09:42:10 -04:00
ap_system.alt_sensor_flag = true;
2012-08-21 23:19:50 -03:00
#endif
}
// save GPS time so we don't get duplicate reads
last_gps_time = g_gps->time;
}
2010-12-19 12:40:33 -04:00
}
2011-02-17 05:36:33 -04:00
2012-12-08 01:23:32 -04:00
// set_yaw_mode - update yaw mode and initialise any variables required
bool set_yaw_mode(uint8_t new_yaw_mode)
{
// boolean to ensure proper initialisation of throttle modes
bool yaw_initialised = false;
// return immediately if no change
if( new_yaw_mode == yaw_mode ) {
return true;
}
switch( new_yaw_mode ) {
case YAW_HOLD:
case YAW_ACRO:
yaw_initialised = true;
break;
case YAW_LOOK_AT_NEXT_WP:
if( ap.home_is_set ) {
yaw_initialised = true;
}
break;
case YAW_LOOK_AT_LOCATION:
if( ap.home_is_set ) {
// update bearing - assumes yaw_look_at_WP has been intialised before set_yaw_mode was called
yaw_look_at_WP_bearing = get_bearing_cd(¤t_loc, &yaw_look_at_WP);
yaw_initialised = true;
}
break;
case YAW_LOOK_AT_HEADING:
yaw_initialised = true;
break;
case YAW_LOOK_AT_HOME:
if( ap.home_is_set ) {
yaw_initialised = true;
}
break;
case YAW_TOY:
yaw_initialised = true;
break;
case YAW_LOOK_AHEAD:
if( ap.home_is_set ) {
yaw_initialised = true;
}
break;
}
// if initialisation has been successful update the yaw mode
if( yaw_initialised ) {
yaw_mode = new_yaw_mode;
}
// return success or failure
return yaw_initialised;
}
// update_yaw_mode - run high level yaw controllers
// 100hz update rate
2011-09-04 21:15:36 -03:00
void update_yaw_mode(void)
{
2012-08-21 23:19:50 -03:00
switch(yaw_mode) {
2012-12-08 01:23:32 -04:00
case YAW_HOLD:
// heading hold at heading held in nav_yaw but allow input from pilot
get_yaw_rate_stabilized_ef(g.rc_4.control_in);
break;
2012-08-21 23:19:50 -03:00
case YAW_ACRO:
2012-12-08 01:23:32 -04:00
// pilot controlled yaw using rate controller
2012-10-14 05:47:46 -03:00
if(g.axis_enabled) {
2012-10-18 11:24:34 -03:00
get_yaw_rate_stabilized_ef(g.rc_4.control_in);
2012-10-14 05:47:46 -03:00
}else{
get_acro_yaw(g.rc_4.control_in);
}
2012-08-21 23:19:50 -03:00
break;
2012-12-08 01:23:32 -04:00
case YAW_LOOK_AT_NEXT_WP:
// point towards next waypoint (no pilot input accepted)
// we don't use wp_bearing because we don't want the copter to turn too much during flight
nav_yaw = get_yaw_slew(nav_yaw, original_wp_bearing, AUTO_YAW_SLEW_RATE);
get_stabilize_yaw(nav_yaw);
2012-08-21 23:19:50 -03:00
2012-12-08 01:23:32 -04:00
// if there is any pilot input, switch to YAW_HOLD mode for the next iteration
if( g.rc_4.control_in != 0 ) {
set_yaw_mode(YAW_HOLD);
}
break;
case YAW_LOOK_AT_LOCATION:
// point towards a location held in yaw_look_at_WP (no pilot input accepted)
nav_yaw = get_yaw_slew(nav_yaw, yaw_look_at_WP_bearing, AUTO_YAW_SLEW_RATE);
get_stabilize_yaw(nav_yaw);
// if there is any pilot input, switch to YAW_HOLD mode for the next iteration
if( g.rc_4.control_in != 0 ) {
set_yaw_mode(YAW_HOLD);
}
2012-08-21 23:19:50 -03:00
break;
case YAW_LOOK_AT_HOME:
2012-12-08 01:23:32 -04:00
// keep heading always pointing at home with no pilot input allowed
nav_yaw = get_yaw_slew(nav_yaw, home_bearing, AUTO_YAW_SLEW_RATE);
2012-10-01 02:02:49 -03:00
get_stabilize_yaw(nav_yaw);
2012-12-08 01:23:32 -04:00
// if there is any pilot input, switch to YAW_HOLD mode for the next iteration
if( g.rc_4.control_in != 0 ) {
set_yaw_mode(YAW_HOLD);
}
2012-08-21 23:19:50 -03:00
break;
2012-12-08 01:23:32 -04:00
case YAW_LOOK_AT_HEADING:
// keep heading pointing in the direction held in yaw_look_at_heading with no pilot input allowed
nav_yaw = get_yaw_slew(nav_yaw, yaw_look_at_heading, yaw_look_at_heading_slew);
2012-10-01 02:02:49 -03:00
get_stabilize_yaw(nav_yaw);
2012-08-21 23:19:50 -03:00
break;
2012-12-08 01:23:32 -04:00
2012-11-26 22:36:32 -04:00
case YAW_LOOK_AHEAD:
2012-12-04 14:26:41 -04:00
// Commanded Yaw to automatically look ahead.
2012-12-08 01:23:32 -04:00
get_look_ahead_yaw(g.rc_4.control_in);
break;
#if TOY_LOOKUP == TOY_EXTERNAL_MIXER
case YAW_TOY:
// update to allow external roll/yaw mixing
// keep heading always pointing at home with no pilot input allowed
nav_yaw = get_yaw_slew(nav_yaw, home_bearing, AUTO_YAW_SLEW_RATE);
get_stabilize_yaw(nav_yaw);
break;
#endif
}
}
// set_roll_pitch_mode - update roll/pitch mode and initialise any variables as required
bool set_roll_pitch_mode(uint8_t new_roll_pitch_mode)
{
// boolean to ensure proper initialisation of throttle modes
bool roll_pitch_initialised = false;
// return immediately if no change
if( new_roll_pitch_mode == roll_pitch_mode ) {
return true;
}
switch( new_roll_pitch_mode ) {
case ROLL_PITCH_STABLE:
case ROLL_PITCH_ACRO:
case ROLL_PITCH_AUTO:
case ROLL_PITCH_STABLE_OF:
case ROLL_PITCH_TOY:
roll_pitch_initialised = true;
break;
2013-01-22 05:17:19 -04:00
2013-02-18 01:58:24 -04:00
case ROLL_PITCH_LOITER:
2013-01-22 05:17:19 -04:00
// require gps lock
if( ap.home_is_set ) {
roll_pitch_initialised = true;
}
break;
2012-12-08 01:23:32 -04:00
}
// if initialisation has been successful update the yaw mode
if( roll_pitch_initialised ) {
roll_pitch_mode = new_roll_pitch_mode;
2012-08-21 23:19:50 -03:00
}
2012-12-08 01:23:32 -04:00
// return success or failure
return roll_pitch_initialised;
2011-09-04 21:15:36 -03:00
}
2011-07-21 20:14:53 -03:00
2012-12-08 01:23:32 -04:00
// update_roll_pitch_mode - run high level roll and pitch controllers
// 100hz update rate
2011-09-04 21:15:36 -03:00
void update_roll_pitch_mode(void)
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
switch(roll_pitch_mode) {
2012-12-14 00:12:39 -04:00
case ROLL_PITCH_ACRO:
2013-02-18 02:26:17 -04:00
// copy user input for reporting purposes
control_roll = g.rc_1.control_in;
control_pitch = g.rc_2.control_in;
2012-11-26 22:02:41 -04:00
#if FRAME_CONFIG == HELI_FRAME
if(g.axis_enabled) {
2012-10-18 11:24:34 -03:00
get_roll_rate_stabilized_ef(g.rc_1.control_in);
get_pitch_rate_stabilized_ef(g.rc_2.control_in);
2012-08-21 23:19:50 -03:00
}else{
// ACRO does not get SIMPLE mode ability
if (motors.flybar_mode == 1) {
g.rc_1.servo_out = g.rc_1.control_in;
g.rc_2.servo_out = g.rc_2.control_in;
} else {
2012-10-01 02:02:49 -03:00
get_acro_roll(g.rc_1.control_in);
get_acro_pitch(g.rc_2.control_in);
2012-08-21 23:19:50 -03:00
}
2012-11-26 22:02:41 -04:00
}
#else // !HELI_FRAME
if(g.axis_enabled) {
get_roll_rate_stabilized_ef(g.rc_1.control_in);
get_pitch_rate_stabilized_ef(g.rc_2.control_in);
}else{
// ACRO does not get SIMPLE mode ability
2012-10-01 02:02:49 -03:00
get_acro_roll(g.rc_1.control_in);
get_acro_pitch(g.rc_2.control_in);
2012-11-26 22:02:41 -04:00
}
#endif // HELI_FRAME
2012-08-21 23:19:50 -03:00
break;
case ROLL_PITCH_STABLE:
// apply SIMPLE mode transform
2012-11-11 09:42:10 -04:00
if(ap.simple_mode && ap_system.new_radio_frame) {
2012-08-21 23:19:50 -03:00
update_simple_mode();
}
control_roll = g.rc_1.control_in;
control_pitch = g.rc_2.control_in;
2012-10-21 18:32:39 -03:00
2012-10-01 02:02:49 -03:00
get_stabilize_roll(control_roll);
get_stabilize_pitch(control_pitch);
2012-08-21 23:19:50 -03:00
break;
case ROLL_PITCH_AUTO:
2013-02-18 02:26:17 -04:00
// copy user input for reporting purposes
control_roll = g.rc_1.control_in;
control_pitch = g.rc_2.control_in;
2013-02-18 01:58:24 -04:00
// copy latest output from nav controller to stabilize controller
2013-02-18 02:26:17 -04:00
nav_roll += constrain_int32(wrap_180(auto_roll - nav_roll), -g.auto_slew_rate.get(), g.auto_slew_rate.get()); // 40 deg a second
nav_pitch += constrain_int32(wrap_180(auto_pitch - nav_pitch), -g.auto_slew_rate.get(), g.auto_slew_rate.get()); // 40 deg a second
2013-02-18 01:58:24 -04:00
get_stabilize_roll(nav_roll);
get_stabilize_pitch(nav_pitch);
2012-08-21 23:19:50 -03:00
2013-02-18 01:58:24 -04:00
// copy control_roll and pitch for reporting purposes
control_roll = nav_roll;
control_pitch = nav_pitch;
2012-08-21 23:19:50 -03:00
break;
case ROLL_PITCH_STABLE_OF:
// apply SIMPLE mode transform
2012-11-11 09:42:10 -04:00
if(ap.simple_mode && ap_system.new_radio_frame) {
2012-08-21 23:19:50 -03:00
update_simple_mode();
}
control_roll = g.rc_1.control_in;
control_pitch = g.rc_2.control_in;
// mix in user control with optical flow
2012-10-01 02:02:49 -03:00
get_stabilize_roll(get_of_roll(control_roll));
get_stabilize_pitch(get_of_pitch(control_pitch));
2012-08-21 23:19:50 -03:00
break;
// THOR
// a call out to the main toy logic
case ROLL_PITCH_TOY:
roll_pitch_toy();
break;
2013-01-22 05:17:19 -04:00
2013-02-18 01:58:24 -04:00
case ROLL_PITCH_LOITER:
2013-01-22 05:17:19 -04:00
// apply SIMPLE mode transform
if(ap.simple_mode && ap_system.new_radio_frame) {
update_simple_mode();
}
2013-01-25 02:11:09 -04:00
// copy user input for logging purposes
2013-01-22 05:17:19 -04:00
control_roll = g.rc_1.control_in;
control_pitch = g.rc_2.control_in;
2013-01-25 02:11:09 -04:00
// update loiter target from user controls - max velocity is 5.0 m/s
if( control_roll != 0 || control_pitch != 0 ) {
loiter_set_pos_from_velocity(-control_pitch/(2*4.5), control_roll/(2*4.5),0.01f);
}
// copy latest output from nav controller to stabilize controller
2013-02-18 02:26:17 -04:00
nav_roll += constrain_int32(wrap_180(auto_roll - nav_roll), -g.auto_slew_rate.get(), g.auto_slew_rate.get()); // 40 deg a second
nav_pitch += constrain_int32(wrap_180(auto_pitch - nav_pitch), -g.auto_slew_rate.get(), g.auto_slew_rate.get()); // 40 deg a second
2013-02-08 04:51:56 -04:00
get_stabilize_roll(nav_roll);
get_stabilize_pitch(nav_pitch);
break;
2012-08-21 23:19:50 -03:00
}
2012-12-14 00:12:39 -04:00
2012-11-26 19:49:24 -04:00
#if FRAME_CONFIG != HELI_FRAME
2012-08-21 23:19:50 -03:00
if(g.rc_3.control_in == 0 && control_mode <= ACRO) {
reset_rate_I();
reset_stability_I();
}
2012-11-26 19:49:24 -04:00
#endif //HELI_FRAME
2012-08-21 23:19:50 -03:00
2012-11-11 09:42:10 -04:00
if(ap_system.new_radio_frame) {
2012-08-21 23:19:50 -03:00
// clear new radio frame info
2012-11-11 09:42:10 -04:00
ap_system.new_radio_frame = false;
2012-08-21 23:19:50 -03:00
}
2012-01-04 02:54:29 -04:00
}
// new radio frame is used to make sure we only call this at 50hz
void update_simple_mode(void)
{
2012-12-12 19:46:20 -04:00
static uint8_t simple_counter = 0; // State machine counter for Simple Mode
2012-08-21 23:19:50 -03:00
static float simple_sin_y=0, simple_cos_x=0;
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
// used to manage state machine
// which improves speed of function
simple_counter++;
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
int16_t delta = wrap_360(ahrs.yaw_sensor - initial_simple_bearing)/100;
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
if (simple_counter == 1) {
// roll
2013-01-10 14:42:24 -04:00
simple_cos_x = sinf(radians(90 - delta));
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
}else if (simple_counter > 2) {
// pitch
2013-01-10 14:42:24 -04:00
simple_sin_y = cosf(radians(90 - delta));
2012-08-21 23:19:50 -03:00
simple_counter = 0;
}
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
// Rotate input by the initial bearing
int16_t _roll = g.rc_1.control_in * simple_cos_x + g.rc_2.control_in * simple_sin_y;
int16_t _pitch = -(g.rc_1.control_in * simple_sin_y - g.rc_2.control_in * simple_cos_x);
2012-01-04 02:54:29 -04:00
2012-08-21 23:19:50 -03:00
g.rc_1.control_in = _roll;
g.rc_2.control_in = _pitch;
2011-09-04 21:15:36 -03:00
}
2011-07-10 21:47:08 -03:00
2013-01-27 10:48:07 -04:00
// update_super_simple_bearing - adjusts simple bearing based on location
2013-01-24 00:36:55 -04:00
// should be called after home_bearing has been updated
2013-01-27 10:48:07 -04:00
void update_super_simple_bearing()
2013-01-24 00:36:55 -04:00
{
// are we in SIMPLE mode?
if(ap.simple_mode && g.super_simple) {
// get distance to home
if(home_distance > SUPER_SIMPLE_RADIUS) { // 10m from home
// we reset the angular offset to be a vector from home to the quad
initial_simple_bearing = wrap_360(home_bearing+18000);
}
}
}
2012-11-24 03:45:28 -04:00
// set_throttle_mode - sets the throttle mode and initialises any variables as required
bool set_throttle_mode( uint8_t new_throttle_mode )
{
// boolean to ensure proper initialisation of throttle modes
bool throttle_initialised = false;
2012-12-08 01:23:32 -04:00
// return immediately if no change
if( new_throttle_mode == throttle_mode ) {
return true;
}
2012-11-24 03:45:28 -04:00
// initialise any variables required for the new throttle mode
switch(new_throttle_mode) {
case THROTTLE_MANUAL:
case THROTTLE_MANUAL_TILT_COMPENSATED:
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // this controller does not use accel based throttle controller
2013-01-08 01:45:12 -04:00
altitude_error = 0; // clear altitude error reported to GCS
2012-11-24 03:45:28 -04:00
throttle_initialised = true;
break;
2012-12-03 10:05:14 -04:00
case THROTTLE_ACCELERATION: // pilot inputs the desired acceleration
if( g.throttle_accel_enabled ) { // this throttle mode requires use of the accel based throttle controller
2013-01-08 01:45:12 -04:00
altitude_error = 0; // clear altitude error reported to GCS
2012-12-03 10:05:14 -04:00
throttle_initialised = true;
}
break;
2012-11-24 03:45:28 -04:00
case THROTTLE_RATE:
2013-01-08 01:45:12 -04:00
altitude_error = 0; // clear altitude error reported to GCS
throttle_initialised = true;
break;
2013-01-08 03:41:07 -04:00
2012-11-24 03:45:28 -04:00
case THROTTLE_STABILIZED_RATE:
case THROTTLE_DIRECT_ALT:
2013-01-08 03:41:07 -04:00
controller_desired_alt = current_loc.alt; // reset controller desired altitude to current altitude
2012-11-24 03:45:28 -04:00
throttle_initialised = true;
break;
case THROTTLE_HOLD:
case THROTTLE_AUTO:
2013-01-08 03:41:07 -04:00
controller_desired_alt = current_loc.alt; // reset controller desired altitude to current altitude
2012-11-24 03:45:28 -04:00
set_new_altitude(current_loc.alt); // by default hold the current altitude
2013-01-11 23:20:37 -04:00
if ( throttle_mode <= THROTTLE_MANUAL_TILT_COMPENSATED ) { // reset the alt hold I terms if previous throttle mode was manual
2012-11-24 03:45:28 -04:00
reset_throttle_I();
2013-01-31 03:30:03 -04:00
set_accel_throttle_I_from_pilot_throttle(get_pilot_desired_throttle(g.rc_3.control_in));
2012-11-24 03:45:28 -04:00
}
throttle_initialised = true;
break;
case THROTTLE_LAND:
set_land_complete(false); // mark landing as incomplete
2012-11-24 09:50:09 -04:00
land_detector = 0; // A counter that goes up if our climb rate stalls out.
2013-01-08 03:41:07 -04:00
controller_desired_alt = current_loc.alt; // reset controller desired altitude to current altitude
// Set target altitude to LAND_START_ALT if we are high, below this altitude the get_throttle_rate_stabilized will take care of setting the next_WP.alt
if (current_loc.alt >= LAND_START_ALT) {
set_new_altitude(LAND_START_ALT);
2012-12-29 00:51:14 -04:00
}
2013-01-08 03:41:07 -04:00
throttle_initialised = true;
2012-12-29 00:51:14 -04:00
break;
2012-11-24 03:45:28 -04:00
default:
2012-12-03 10:05:14 -04:00
// To-Do: log an error message to the dataflash or tlogs instead of printing to the serial port
2012-11-24 03:45:28 -04:00
cliSerial->printf_P(PSTR("Unsupported throttle mode: %d!!"),new_throttle_mode);
break;
}
// update the throttle mode
if( throttle_initialised ) {
throttle_mode = new_throttle_mode;
// reset some variables used for logging
desired_climb_rate = 0;
nav_throttle = 0;
}
// return success or failure
return throttle_initialised;
}
2012-12-08 01:23:32 -04:00
// update_throttle_mode - run high level throttle controllers
2012-05-17 14:55:13 -03:00
// 50 hz update rate
2011-09-04 21:15:36 -03:00
void update_throttle_mode(void)
{
2012-11-23 02:57:49 -04:00
int16_t pilot_climb_rate;
2013-01-30 11:25:41 -04:00
int16_t pilot_throttle_scaled;
2012-11-23 02:57:49 -04:00
2012-11-10 01:39:41 -04:00
if(ap.do_flip) // this is pretty bad but needed to flip in AP modes.
2012-08-21 23:19:50 -03:00
return;
2012-11-23 02:57:49 -04:00
// do not run throttle controllers if motors disarmed
if( !motors.armed() ) {
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // do not allow the accel based throttle to override our command
2012-11-23 02:57:49 -04:00
return;
2012-08-21 23:19:50 -03:00
}
2012-11-26 20:37:20 -04:00
#if FRAME_CONFIG == HELI_FRAME
2013-01-08 01:45:12 -04:00
if (control_mode == STABILIZE){
2012-11-26 20:37:20 -04:00
motors.stab_throttle = true;
} else {
motors.stab_throttle = false;
}
#endif // HELI_FRAME
2012-08-21 23:19:50 -03:00
switch(throttle_mode) {
2012-11-23 02:57:49 -04:00
2012-08-21 23:19:50 -03:00
case THROTTLE_MANUAL:
2012-11-23 02:57:49 -04:00
// completely manual throttle
if(g.rc_3.control_in <= 0){
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-11-23 02:57:49 -04:00
}else{
// send pilot's output directly to motors
2013-01-30 11:25:41 -04:00
pilot_throttle_scaled = get_pilot_desired_throttle(g.rc_3.control_in);
set_throttle_out(pilot_throttle_scaled, false);
2012-11-23 02:57:49 -04:00
// update estimate of throttle cruise
2012-12-08 16:12:39 -04:00
#if FRAME_CONFIG == HELI_FRAME
update_throttle_cruise(motors.coll_out);
#else
2013-01-30 11:25:41 -04:00
update_throttle_cruise(pilot_throttle_scaled);
2012-12-08 16:12:39 -04:00
#endif //HELI_FRAME
2012-12-14 00:12:39 -04:00
2012-11-23 02:57:49 -04:00
// check if we've taken off yet
if (!ap.takeoff_complete && motors.armed()) {
2013-01-30 11:25:41 -04:00
if (pilot_throttle_scaled > g.throttle_cruise) {
2012-11-23 02:57:49 -04:00
// we must be in the air by now
set_takeoff_complete(true);
}
}
}
break;
case THROTTLE_MANUAL_TILT_COMPENSATED:
// manual throttle but with angle boost
if (g.rc_3.control_in <= 0) {
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false); // no need for angle boost with zero throttle
2012-11-23 02:57:49 -04:00
}else{
2013-01-30 11:25:41 -04:00
pilot_throttle_scaled = get_pilot_desired_throttle(g.rc_3.control_in);
set_throttle_out(pilot_throttle_scaled, true);
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
// update estimate of throttle cruise
2012-12-08 16:12:39 -04:00
#if FRAME_CONFIG == HELI_FRAME
update_throttle_cruise(motors.coll_out);
#else
2013-01-30 11:25:41 -04:00
update_throttle_cruise(pilot_throttle_scaled);
2012-12-08 16:12:39 -04:00
#endif //HELI_FRAME
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
if (!ap.takeoff_complete && motors.armed()) {
2013-01-30 11:25:41 -04:00
if (pilot_throttle_scaled > g.throttle_cruise) {
2012-08-21 23:19:50 -03:00
// we must be in the air by now
2012-11-10 01:39:41 -04:00
set_takeoff_complete(true);
2012-08-21 23:19:50 -03:00
}
}
2012-11-23 02:57:49 -04:00
}
break;
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_ACCELERATION:
// pilot inputs the desired acceleration
if(g.rc_3.control_in <= 0){
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // do not allow the accel based throttle to override our command
2012-08-21 23:19:50 -03:00
}else{
2012-11-23 02:57:49 -04:00
int16_t desired_acceleration = get_pilot_desired_acceleration(g.rc_3.control_in);
set_throttle_accel_target(desired_acceleration);
}
2012-11-24 00:41:17 -04:00
break;
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_RATE:
// pilot inputs the desired climb rate. Note this is the unstabilized rate controller
if(g.rc_3.control_in <= 0){
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // do not allow the accel based throttle to override our command
2012-11-23 02:57:49 -04:00
}else{
pilot_climb_rate = get_pilot_desired_climb_rate(g.rc_3.control_in);
get_throttle_rate(pilot_climb_rate);
2012-08-21 23:19:50 -03:00
}
break;
2012-11-23 02:57:49 -04:00
case THROTTLE_STABILIZED_RATE:
2012-12-03 10:05:14 -04:00
// pilot inputs the desired climb rate. Note this is the stabilized rate controller
2012-11-23 02:57:49 -04:00
if(g.rc_3.control_in <= 0){
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // do not allow the accel based throttle to override our command
2013-01-08 01:45:12 -04:00
altitude_error = 0; // clear altitude error reported to GCS - normally underlying alt hold controller updates altitude error reported to GCS
2012-11-23 02:57:49 -04:00
}else{
pilot_climb_rate = get_pilot_desired_climb_rate(g.rc_3.control_in);
get_throttle_rate_stabilized(pilot_climb_rate);
2012-08-28 19:28:18 -03:00
}
2012-11-23 02:57:49 -04:00
break;
2012-08-28 19:28:18 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_DIRECT_ALT:
// pilot inputs a desired altitude from 0 ~ 10 meters
if(g.rc_3.control_in <= 0){
2012-11-24 00:41:17 -04:00
set_throttle_out(0, false);
2012-12-03 10:05:14 -04:00
throttle_accel_deactivate(); // do not allow the accel based throttle to override our command
2013-01-08 01:45:12 -04:00
altitude_error = 0; // clear altitude error reported to GCS - normally underlying alt hold controller updates altitude error reported to GCS
2012-11-23 02:57:49 -04:00
}else{
int32_t desired_alt = get_pilot_desired_direct_alt(g.rc_3.control_in);
2013-01-08 03:41:07 -04:00
get_throttle_althold_with_slew(desired_alt, g.auto_velocity_z_min, g.auto_velocity_z_max);
2012-08-21 23:19:50 -03:00
}
2012-11-23 02:57:49 -04:00
break;
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_HOLD:
// alt hold plus pilot input of climb rate
pilot_climb_rate = get_pilot_desired_climb_rate(g.rc_3.control_in);
2013-01-10 08:43:13 -04:00
if( sonar_alt_health >= SONAR_ALT_HEALTH_MAX ) {
// if sonar is ok, use surface tracking
get_throttle_surface_tracking(pilot_climb_rate);
}else{
// if no sonar fall back stabilize rate controller
get_throttle_rate_stabilized(pilot_climb_rate);
}
2012-11-23 02:57:49 -04:00
break;
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_AUTO:
// auto pilot altitude controller with target altitude held in next_WP.alt
if(motors.auto_armed() == true) {
2013-01-08 03:41:07 -04:00
get_throttle_althold_with_slew(next_WP.alt, g.auto_velocity_z_min, g.auto_velocity_z_max);
2012-08-21 23:19:50 -03:00
}
2012-11-23 02:57:49 -04:00
break;
2012-08-21 23:19:50 -03:00
2012-11-23 02:57:49 -04:00
case THROTTLE_LAND:
// landing throttle controller
get_throttle_land();
2012-08-21 23:19:50 -03:00
break;
}
2010-12-19 12:40:33 -04:00
}
2011-07-17 07:31:46 -03:00
static void read_AHRS(void)
2010-12-19 12:40:33 -04:00
{
2012-08-21 23:19:50 -03:00
// Perform IMU calculations and get attitude info
//-----------------------------------------------
#if HIL_MODE != HIL_MODE_DISABLED
// update hil before ahrs update
2013-01-08 01:45:12 -04:00
gcs_check_input();
2012-08-21 23:19:50 -03:00
#endif
ahrs.update();
2012-11-05 00:32:38 -04:00
omega = ins.get_gyro();
2012-09-29 12:25:40 -03:00
#if SECONDARY_DMP_ENABLED == ENABLED
ahrs2.update();
#endif
2011-01-23 12:40:03 -04:00
}
2011-02-13 18:32:34 -04:00
2011-07-17 07:31:46 -03:00
static void update_trig(void){
2012-08-21 23:19:50 -03:00
Vector2f yawvector;
Matrix3f temp = ahrs.get_dcm_matrix();
2011-02-17 05:36:33 -04:00
2012-08-21 23:19:50 -03:00
yawvector.x = temp.a.x; // sin
yawvector.y = temp.b.x; // cos
yawvector.normalize();
2011-02-13 18:32:34 -04:00
2012-08-21 23:19:50 -03:00
cos_pitch_x = safe_sqrt(1 - (temp.c.x * temp.c.x)); // level = 1
2012-12-14 00:12:39 -04:00
cos_roll_x = temp.c.z / cos_pitch_x; // level = 1
2011-02-17 05:36:33 -04:00
2012-12-14 00:12:39 -04:00
cos_pitch_x = constrain(cos_pitch_x, 0, 1.0);
2012-02-23 19:44:55 -04:00
// this relies on constrain() of infinity doing the right thing,
// which it does do in avr-libc
2012-12-14 00:12:39 -04:00
cos_roll_x = constrain(cos_roll_x, -1.0, 1.0);
2011-07-10 21:47:08 -03:00
2012-12-14 00:12:39 -04:00
sin_yaw_y = yawvector.x; // 1y = north
cos_yaw_x = yawvector.y; // 0x = north
2011-09-16 03:33:00 -03:00
2012-10-01 02:02:49 -03:00
// added to convert earth frame to body frame for rate controllers
2012-12-14 00:12:39 -04:00
sin_pitch = -temp.c.x;
sin_roll = temp.c.y / cos_pitch_x;
2012-10-01 02:02:49 -03:00
2013-01-22 05:17:19 -04:00
sin_yaw = constrain(temp.b.x/cos_pitch_x, -1.0, 1.0);
cos_yaw = constrain(temp.a.x/cos_pitch_x, -1.0, 1.0);
2012-08-21 23:19:50 -03:00
//flat:
// 0 ° = cos_yaw: 0.00, sin_yaw: 1.00,
// 90° = cos_yaw: 1.00, sin_yaw: 0.00,
// 180 = cos_yaw: 0.00, sin_yaw: -1.00,
// 270 = cos_yaw: -1.00, sin_yaw: 0.00,
2011-02-17 05:36:33 -04:00
}
2011-02-20 19:09:28 -04:00
2013-02-01 23:00:09 -04:00
// read baro and sonar altitude at 10hz
2011-09-04 21:15:36 -03:00
static void update_altitude()
2011-02-21 00:30:56 -04:00
{
2012-08-21 23:19:50 -03:00
#if HIL_MODE == HIL_MODE_ATTITUDE
// we are in the SIM, fake out the baro and Sonar
2013-02-01 23:00:09 -04:00
baro_alt = g_gps->altitude - gps_base_alt;
2012-12-21 01:03:47 -04:00
if(g.sonar_enabled) {
2013-02-01 23:00:09 -04:00
sonar_alt = baro_alt;
2012-12-21 01:03:47 -04:00
}
2012-08-21 23:19:50 -03:00
#else
2013-02-01 23:00:09 -04:00
// read in baro altitude
2012-12-21 01:03:47 -04:00
baro_alt = read_barometer();
2012-08-21 23:19:50 -03:00
2013-02-01 23:00:09 -04:00
// read in sonar altitude
2013-01-31 04:00:28 -04:00
sonar_alt = read_sonar();
2012-12-21 01:03:47 -04:00
#endif // HIL_MODE == HIL_MODE_ATTITUDE
2012-08-21 23:19:50 -03:00
2013-02-01 23:00:09 -04:00
// write altitude info to dataflash logs
if ((g.log_bitmask & MASK_LOG_CTUN) && motors.armed()) {
Log_Write_Control_Tuning();
2012-08-21 23:19:50 -03:00
}
2011-03-26 03:35:52 -03:00
}
2011-07-17 07:31:46 -03:00
static void tuning(){
2013-01-10 14:42:24 -04:00
tuning_value = (float)g.rc_6.control_in / 1000.0f;
2012-08-21 23:19:50 -03:00
g.rc_6.set_range(g.radio_tuning_low,g.radio_tuning_high); // 0 to 1
switch(g.radio_tuning) {
case CH6_RATE_KD:
g.pid_rate_roll.kD(tuning_value);
g.pid_rate_pitch.kD(tuning_value);
break;
case CH6_STABILIZE_KP:
g.pi_stabilize_roll.kP(tuning_value);
g.pi_stabilize_pitch.kP(tuning_value);
break;
case CH6_STABILIZE_KI:
g.pi_stabilize_roll.kI(tuning_value);
g.pi_stabilize_pitch.kI(tuning_value);
break;
case CH6_ACRO_KP:
g.acro_p = tuning_value;
break;
case CH6_RATE_KP:
g.pid_rate_roll.kP(tuning_value);
g.pid_rate_pitch.kP(tuning_value);
break;
case CH6_RATE_KI:
g.pid_rate_roll.kI(tuning_value);
g.pid_rate_pitch.kI(tuning_value);
break;
case CH6_YAW_KP:
g.pi_stabilize_yaw.kP(tuning_value);
break;
case CH6_YAW_KI:
g.pi_stabilize_yaw.kI(tuning_value);
break;
case CH6_YAW_RATE_KP:
g.pid_rate_yaw.kP(tuning_value);
break;
case CH6_YAW_RATE_KD:
g.pid_rate_yaw.kD(tuning_value);
break;
case CH6_THROTTLE_KP:
g.pid_throttle.kP(tuning_value);
break;
2012-11-25 05:02:45 -04:00
case CH6_THROTTLE_KI:
g.pid_throttle.kI(tuning_value);
break;
2012-12-17 01:36:05 -04:00
case CH6_THROTTLE_KD:
g.pid_throttle.kD(tuning_value);
break;
2012-08-21 23:19:50 -03:00
case CH6_TOP_BOTTOM_RATIO:
motors.top_bottom_ratio = tuning_value;
break;
case CH6_RELAY:
if (g.rc_6.control_in > 525) relay.on();
if (g.rc_6.control_in < 475) relay.off();
break;
case CH6_TRAVERSE_SPEED:
g.waypoint_speed_max = g.rc_6.control_in;
break;
case CH6_LOITER_KP:
g.pi_loiter_lat.kP(tuning_value);
g.pi_loiter_lon.kP(tuning_value);
break;
case CH6_LOITER_KI:
g.pi_loiter_lat.kI(tuning_value);
g.pi_loiter_lon.kI(tuning_value);
break;
case CH6_NAV_KP:
g.pid_nav_lat.kP(tuning_value);
g.pid_nav_lon.kP(tuning_value);
break;
case CH6_LOITER_RATE_KP:
g.pid_loiter_rate_lon.kP(tuning_value);
g.pid_loiter_rate_lat.kP(tuning_value);
break;
case CH6_LOITER_RATE_KI:
g.pid_loiter_rate_lon.kI(tuning_value);
g.pid_loiter_rate_lat.kI(tuning_value);
break;
case CH6_LOITER_RATE_KD:
g.pid_loiter_rate_lon.kD(tuning_value);
g.pid_loiter_rate_lat.kD(tuning_value);
break;
2012-12-09 03:44:42 -04:00
case CH6_NAV_KI:
2012-08-21 23:19:50 -03:00
g.pid_nav_lat.kI(tuning_value);
g.pid_nav_lon.kI(tuning_value);
break;
#if FRAME_CONFIG == HELI_FRAME
case CH6_HELI_EXTERNAL_GYRO:
motors.ext_gyro_gain = tuning_value;
break;
2012-07-28 04:22:35 -03:00
#endif
2012-08-21 23:19:50 -03:00
case CH6_THR_HOLD_KP:
g.pi_alt_hold.kP(tuning_value);
break;
case CH6_OPTFLOW_KP:
g.pid_optflow_roll.kP(tuning_value);
g.pid_optflow_pitch.kP(tuning_value);
break;
case CH6_OPTFLOW_KI:
g.pid_optflow_roll.kI(tuning_value);
g.pid_optflow_pitch.kI(tuning_value);
break;
case CH6_OPTFLOW_KD:
g.pid_optflow_roll.kD(tuning_value);
g.pid_optflow_pitch.kD(tuning_value);
break;
#if HIL_MODE != HIL_MODE_ATTITUDE // do not allow modifying _kp or _kp_yaw gains in HIL mode
case CH6_AHRS_YAW_KP:
ahrs._kp_yaw.set(tuning_value);
break;
case CH6_AHRS_KP:
ahrs._kp.set(tuning_value);
break;
#endif
2012-11-07 06:03:30 -04:00
case CH6_INAV_TC:
2013-02-18 01:58:24 -04:00
// To-Do: allowing tuning TC for xy and z separately
2012-11-07 06:03:30 -04:00
inertial_nav.set_time_constant_xy(tuning_value);
inertial_nav.set_time_constant_z(tuning_value);
2012-12-07 00:01:40 -04:00
break;
2012-11-24 09:50:09 -04:00
case CH6_THR_ACCEL_KP:
g.pid_throttle_accel.kP(tuning_value);
break;
case CH6_THR_ACCEL_KI:
g.pid_throttle_accel.kI(tuning_value);
break;
case CH6_THR_ACCEL_KD:
g.pid_throttle_accel.kD(tuning_value);
break;
2012-08-21 23:19:50 -03:00
}
2011-05-09 14:40:32 -03:00
}
2012-12-13 16:02:27 -04:00
AP_HAL_MAIN();