Subversion Repositories FlightCtrl

Rev

Rev 1910 | Rev 2025 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <stdlib.h>
#include <avr/io.h>
#include "eeprom.h"
#include "flight.h"
#include "output.h"

// Necessary for external control and motor test
#include "uart0.h"

// for scope debugging
// #include "rc.h"

#include "timer2.h"
#include "attitude.h"
#include "controlMixer.h"
#include "commands.h"
#ifdef USE_MK3MAG
#include "gps.h"
#endif

#define CHECK_MIN_MAX(value, min, max) {if(value < min) value = min; else if(value > max) value = max;}

/*
 * These are no longer maintained, just left at 0. The original implementation just summed the acc.
 * value to them every 2 ms. No filtering or anything. Just a case for an eventual overflow?? Hey???
 */

// int16_t naviAccPitch = 0, naviAccRoll = 0, naviCntAcc = 0;

int8_t pitchPFactor, rollPFactor, yawPFactor;
int8_t pitchDFactor, rollDFactor, yawDFactor;

int32_t IPart[2] = {0,0};

/************************************************************************/
/*  Filter for motor value smoothing (necessary???)                     */
/************************************************************************/
int16_t outputFilter(int16_t newvalue, int16_t oldvalue) {
  switch (dynamicParams.UserParams[5]) {
  case 0:
    return newvalue;
  case 1:
    return (oldvalue + newvalue) / 2;
  case 2:
    if (newvalue > oldvalue)
      return (1 * (int16_t) oldvalue + newvalue) / 2; //mean of old and new
    else
      return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
  case 3:
    if (newvalue < oldvalue)
      return (1 * (int16_t) oldvalue + newvalue) / 2; //mean of old and new
    else
      return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
  default:
    return newvalue;
  }
}

/************************************************************************/
/*  Neutral Readings                                                    */
/************************************************************************/
#define CONTROL_CONFIG_SCALE 10

void flight_setNeutral() {
  MKFlags |= MKFLAG_CALIBRATE;
  // not really used here any more.
  controlMixer_initVariables();
}

void setFlightParameters
(
 uint8_t _pitchPFactor,
 uint8_t _rollPFactor,
 uint8_t _yawPFactor,
 
 uint8_t _pitchDFactor,
 uint8_t _rollDFactor,
 uint8_t _yawDFactor
 ) {
  pitchPFactor = _pitchPFactor;
  rollPFactor = _rollPFactor;
  yawPFactor = _yawPFactor;

  pitchDFactor = _pitchDFactor;
  rollDFactor = _rollDFactor;
  yawDFactor = _yawDFactor;
}

void setNormalFlightParameters(void) {
  setFlightParameters
    (
     dynamicParams.GyroPitchP / CONTROL_CONFIG_SCALE,     // 12 seems good
     dynamicParams.GyroRollP / CONTROL_CONFIG_SCALE,      // 9 seems good
     dynamicParams.GyroYawP / (CONTROL_CONFIG_SCALE/2),   // 24 seems too little

     dynamicParams.GyroPitchD / CONTROL_CONFIG_SCALE,
     dynamicParams.GyroRollD / CONTROL_CONFIG_SCALE,
     dynamicParams.GyroYawD / CONTROL_CONFIG_SCALE
     );
}

void setStableFlightParameters(void) {
  setFlightParameters(0, 0, 0, 0, 0, 0);
}

/************************************************************************/
/*  Main Flight Control                                                 */
/************************************************************************/
void flight_control(void) {
  // Mixer Fractions that are combined for Motor Control
  int16_t yawTerm, throttleTerm, term[2];
   
  // PID controller variables
  int16_t PDPart[2], PDPartYaw;

  static int8_t debugDataTimer = 1;

  // High resolution motor values for smoothing of PID motor outputs
  static int16_t outputFilters[MAX_OUTPUTS];

  uint8_t i;

  // Fire the main flight attitude calculation, including integration of angles.
  // We want that to kick as early as possible, not to delay new AD sampling further.
  calculateFlightAttitude();
  controlMixer_update();
  throttleTerm = control[CONTROL_THROTTLE];

  /************************************************************************/
  /* RC-signal is bad                                                     */
  /************************************************************************/

  if (controlMixer_getSignalQuality() <= SIGNAL_BAD) { // the rc-frame signal is not received or noisy
    RED_ON;
    beepRCAlarm();
    setStableFlightParameters();
  } else {
    commands_handleCommands();
    setNormalFlightParameters();
  }
   
  /************************************************************************/
  /* Calculate control feedback from angle (gyro integral)                */
  /* and angular velocity (gyro signal)                                   */
  /************************************************************************/
  PDPart[PITCH] = ((int32_t) rate_PID[PITCH] * pitchPFactor /
                  (256L / CONTROL_SCALING))
  + (differential[PITCH] * (int16_t) dynamicParams.GyroPitchD) / 16;

  PDPart[ROLL] = ((int32_t) rate_PID[ROLL] * rollPFactor /
                  (256L / CONTROL_SCALING))
  + (differential[ROLL] * (int16_t) dynamicParams.GyroRollD) / 16;

  PDPartYaw = (int32_t) (yawRate * 2 * (int32_t) yawPFactor) / (256L / CONTROL_SCALING)
  + (differential[YAW] * (int16_t) dynamicParams.GyroYawD) / 16;

  /************************************************************************/
  /* Stick signals are positive and gyros are negative...                 */
  /************************************************************************/
  IPart[PITCH] = controlIntegrals[CONTROL_ELEVATOR] - angle[PITCH];
  if (IPart[PITCH] > PITCHROLLOVER180) IPart[PITCH] -= PITCHROLLOVER360;
  else if (IPart[PITCH] <= -PITCHROLLOVER180) IPart[PITCH] += PITCHROLLOVER360;
  if (IPart[PITCH] > HH_RANGE) IPart[PITCH] = HH_RANGE;
  else if (IPart[PITCH] < -HH_RANGE) IPart[PITCH] = -HH_RANGE;

  IPart[ROLL] = controlIntegrals[CONTROL_AILERONS] - angle[ROLL];
  if (IPart[ROLL] > PITCHROLLOVER180) IPart[ROLL] -= PITCHROLLOVER360;
  else if (IPart[ROLL] <= -PITCHROLLOVER180) IPart[ROLL] += PITCHROLLOVER360;
  if (IPart[ROLL] > HH_RANGE) IPart[ROLL] = HH_RANGE;
  else if (IPart[ROLL] < -HH_RANGE) IPart[ROLL] = -HH_RANGE;

  term[PITCH] = control[CONTROL_ELEVATOR] + (staticParams.ControlSigns & 1 ? PDPart[PITCH] : -PDPart[PITCH]);
  term[ROLL] = control[CONTROL_AILERONS] + (staticParams.ControlSigns & 2 ? PDPart[ROLL] : -PDPart[ROLL]);
  yawTerm = control[CONTROL_RUDDER] + (staticParams.ControlSigns & 4 ? PDPartYaw : -PDPartYaw);


  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Universal Mixer
  // Each (pitch, roll, throttle, yaw) term is in the range [0..255 * CONTROL_SCALING].
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  DebugOut.Analog[12] = term[PITCH];
  DebugOut.Analog[13] = term[ROLL];
  DebugOut.Analog[14] = throttleTerm;
  DebugOut.Analog[15] = yawTerm;

  for (i = 0; i < MAX_OUTPUTS; i++) {
    int16_t tmp;
      if (outputTestActive) {
          outputs[i].SetPoint = outputTest[i] * 4;
      } else {
        // Follow the normal order of servos: Ailerons, elevator, throttle, rudder.
        switch(i) {
        case 0: tmp = term[ROLL]; break;
        case 1: tmp = term[PITCH]; break;
        case 2: tmp = throttleTerm - 310; break;
        case 3: tmp = yawTerm; break;
        default: tmp = 0;
        }
      outputFilters[i] = outputFilter(tmp, outputFilters[i]);
      // Now we scale back down to a 0..255 range.
      tmp = outputFilters[i];
      outputs[i].SetPoint = tmp;
    }
  }

  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Debugging
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (!(--debugDataTimer)) {
    debugDataTimer = 24; // update debug outputs at 488 / 24 = 20.3 Hz.
    DebugOut.Analog[0] = (10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
    DebugOut.Analog[1] = (10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
    DebugOut.Analog[2] = yawGyroHeading / GYRO_DEG_FACTOR_YAW;

    DebugOut.Analog[6] = pitchPFactor;
    DebugOut.Analog[7] = rollPFactor;
    DebugOut.Analog[8] = yawPFactor;
    DebugOut.Analog[9] = pitchDFactor;
    DebugOut.Analog[10] = rollDFactor;
    DebugOut.Analog[11] = yawDFactor;

    DebugOut.Analog[18] = (10 * controlIntegrals[CONTROL_ELEVATOR]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
    DebugOut.Analog[19] = (10 * controlIntegrals[CONTROL_AILERONS]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
    DebugOut.Analog[22] = (10 * IPart[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
    DebugOut.Analog[23] = (10 * IPart[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
  }
}