Subversion Repositories FlightCtrl

Rev

Rev 2109 | Rev 2115 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1910 - 1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
 
5
#include "rc.h"
6
#include "controlMixer.h"
7
#include "configuration.h"
8
#include "commands.h"
2099 - 9
#include "output.h"
1910 - 10
 
2099 - 11
// The channel array is 0-based!
1910 - 12
volatile int16_t PPM_in[MAX_CHANNELS];
2099 - 13
volatile uint8_t RCQuality;
2102 - 14
 
1910 - 15
uint8_t lastRCCommand = COMMAND_NONE;
2102 - 16
uint8_t lastFlightMode = FLIGHT_MODE_NONE;
17
 
2110 - 18
#define TIME(s) ((int16_t)(((long)F_CPU/(long)8000)*(float)s))
1910 - 19
/***************************************************************
20
 *  16bit timer 1 is used to decode the PPM-Signal            
21
 ***************************************************************/
22
void RC_Init(void) {
23
  uint8_t sreg = SREG;
24
 
25
  // disable all interrupts before reconfiguration
26
  cli();
27
 
28
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
2099 - 29
  DDRD &= ~(1<<6);
30
  PORTD |= (1<<PORTD6);
1910 - 31
 
32
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
33
  // set as output
2099 - 34
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
1910 - 35
  // low level
2099 - 36
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
1910 - 37
 
38
  // PD3 can't be used if 2nd UART is activated
39
  // because TXD1 is at that port
40
  if (CPUType != ATMEGA644P) {
2099 - 41
    DDRD |= (1<<PORTD3);
42
    PORTD &= ~(1<<PORTD3);
1910 - 43
  }
44
 
45
  // Timer/Counter1 Control Register A, B, C
46
 
47
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
48
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
49
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
50
  // Enable input capture noise cancler (bit: ICNC1=1)
51
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
2099 - 52
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
1910 - 53
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
2099 - 54
  TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10));
1910 - 55
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
2109 - 56
  TCCR1B |= (1 << CS11) | (1 << ICES1) | (1 << ICNC1);
1910 - 57
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
58
 
59
  // Timer/Counter1 Interrupt Mask Register
60
  // Enable Input Capture Interrupt (bit: ICIE1=1)
61
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
62
  // Enable Overflow Interrupt (bit: TOIE1=0)
2099 - 63
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
64
  TIMSK1 |= (1<<ICIE1);
1910 - 65
 
2099 - 66
  RCQuality = 0;
1910 - 67
 
68
  SREG = sreg;
69
}
70
 
71
/********************************************************************/
72
/*         Every time a positive edge is detected at PD6            */
73
/********************************************************************/
74
/*                               t-Frame
2099 - 75
    <----------------------------------------------------------------------->
76
     ____   ______   _____   ________                ______    sync gap      ____
77
    |    | |      | |     | |        |              |      |                |
78
    |    | |      | |     | |        |              |      |                |
1910 - 79
 ___|    |_|      |_|     |_|        |_.............|      |________________|
2099 - 80
    <-----><-------><------><-----------            <------>                <---
1910 - 81
 t0       t1      t2       t4                     tn                     t0
82
 
83
 The PPM-Frame length is 22.5 ms.
84
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
85
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
2099 - 86
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
1910 - 87
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
88
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
89
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
90
 the syncronization gap.
91
 */
2099 - 92
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
2107 - 93
  int16_t signal, tmp;
1910 - 94
  static int16_t index;
95
  static uint16_t oldICR1 = 0;
96
 
97
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
98
  // at the time the edge was detected
99
 
100
  // calculate the time delay to the previous event time which is stored in oldICR1
101
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
102
  // implicit handles a timer overflow 65535 -> 0 the right way.
103
  signal = (uint16_t) ICR1 - oldICR1;
104
  oldICR1 = ICR1;
105
 
2109 - 106
  //sync gap? (3.5 ms < signal < 25.6 ms)
2110 - 107
  if (signal > TIME(3.5)) {
2099 - 108
    index = 0;
1910 - 109
  } else { // within the PPM frame
2099 - 110
    if (index < MAX_CHANNELS) { // PPM24 supports 12 channels
2109 - 111
      // check for valid signal length (0.8 ms < signal < 2.2 ms)
2110 - 112
      if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) {
1910 - 113
        // shift signal to zero symmetric range  -154 to 159
2109 - 114
        //signal -= 3750; // theoretical value
2110 - 115
        signal -= (TIME(1.5) + RC_TRIM); // best value with my Futaba in zero trim.
2099 - 116
        // check for stable signal
2110 - 117
        if (abs(signal - PPM_in[index]) < TIME(0.05)) {
2099 - 118
          if (RCQuality < 200)
119
            RCQuality += 10;
1910 - 120
          else
2099 - 121
            RCQuality = 200;
1910 - 122
        }
2099 - 123
        // If signal is the same as before +/- 1, just keep it there. Naah lets get rid of this slimy sticy stuff.
124
        // if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
125
          // In addition, if the signal is very close to 0, just set it to 0.
126
        if (signal >= -1 && signal <= 1) {
127
          tmp = 0;
128
        //} else {
129
        //  tmp = PPM_in[index];
130
        //  }
131
        } else
132
          tmp = signal;
133
        PPM_in[index] = tmp; // update channel value
1910 - 134
      }
135
      index++; // next channel
2099 - 136
      // demux sum signal for channels 5 to 7 to J3, J4, J5
137
      // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
138
      // channels are usually available at the receiver anyway.
139
      // if(index == 5) J3HIGH; else J3LOW;
140
      // if(index == 6) J4HIGH; else J4LOW;
141
      // if(CPUType != ATMEGA644P) // not used as TXD1
142
      //  {
143
      //    if(index == 7) J5HIGH; else J5LOW;
144
      //  }
1910 - 145
    }
146
  }
147
}
148
 
2099 - 149
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
150
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
151
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
1910 - 152
 
2103 - 153
uint8_t getControlModeSwitch(void) {
2109 - 154
        int16_t channel = RCChannel(CH_MODESWITCH);
2110 - 155
        uint8_t flightMode = channel < -TIME(0.17) ? FLIGHT_MODE_MANUAL : (channel > TIME(0.17) ? FLIGHT_MODE_ANGLES : FLIGHT_MODE_RATE);
2102 - 156
        return flightMode;
157
}
158
 
159
// Gyro calibration is performed as.... well mode switch with no throttle and no airspeed would be nice.
160
// Maybe simply: Very very low throttle.
161
// Throttle xlow for COMMAND_TIMER: GYROCAL (once).
162
// mode switched: CHMOD
163
 
164
uint8_t RC_getCommand(void) {
165
        uint8_t flightMode = getControlModeSwitch();
166
 
167
        if (lastFlightMode != flightMode) {
168
                lastFlightMode = flightMode;
169
                lastRCCommand = COMMAND_CHMOD;
170
                return lastRCCommand;
171
        }
172
 
2103 - 173
        int16_t channel = RCChannel(CH_THROTTLE);
2104 - 174
 
2110 - 175
        if (channel <= -TIME(0.55)) {
2109 - 176
          lastRCCommand = COMMAND_GYROCAL;
2103 - 177
        } else {
178
          lastRCCommand = COMMAND_NONE;
179
        }
2102 - 180
        return lastRCCommand;
181
}
182
 
183
uint8_t RC_getArgument(void) {
184
        return lastFlightMode;
185
}
186
 
1910 - 187
/*
2099 - 188
 * Get Pitch, Roll, Throttle, Yaw values
1910 - 189
 */
2103 - 190
void RC_periodicTaskAndPRYT(int16_t* PRYT) {
2099 - 191
  if (RCQuality) {
192
    RCQuality--;
193
 
2103 - 194
    debugOut.analog[20] = RCChannel(CH_ELEVATOR);
195
    debugOut.analog[21] = RCChannel(CH_AILERONS);
196
    debugOut.analog[22] = RCChannel(CH_RUDDER);
197
    debugOut.analog[23] = RCChannel(CH_THROTTLE);
2102 - 198
 
2109 - 199
    PRYT[CONTROL_ELEVATOR]   = RCChannel(CH_ELEVATOR) / RC_SCALING;
200
    PRYT[CONTROL_AILERONS]   = RCChannel(CH_AILERONS) / RC_SCALING;
201
    PRYT[CONTROL_RUDDER]     = RCChannel(CH_RUDDER)   / RC_SCALING;
202
    PRYT[CONTROL_THROTTLE]   = RCChannel(CH_THROTTLE) / RC_SCALING;
2099 - 203
  } // if RCQuality is no good, we just do nothing.
1910 - 204
}
205
 
206
/*
207
 * Get other channel value
208
 */
209
int16_t RC_getVariable(uint8_t varNum) {
210
  if (varNum < 4)
211
    // 0th variable is 5th channel (1-based) etc.
2110 - 212
    return (RCChannel(varNum + CH_POTS) >> 3) + VARIABLE_OFFSET;
1910 - 213
  /*
214
   * Let's just say:
2099 - 215
   * The RC variable i is hardwired to channel i, i>=4
1910 - 216
   */
2110 - 217
  return (PPM_in[varNum] >> 3) + VARIABLE_OFFSET;
1910 - 218
}
219
 
220
uint8_t RC_getSignalQuality(void) {
2099 - 221
  if (RCQuality >= 160)
1910 - 222
    return SIGNAL_GOOD;
2099 - 223
  if (RCQuality >= 140)
1910 - 224
    return SIGNAL_OK;
2099 - 225
  if (RCQuality >= 120)
1910 - 226
    return SIGNAL_BAD;
227
  return SIGNAL_LOST;
228
}
229
 
230
/*
231
 * To should fired only when the right stick is in the center position.
232
 * This will cause the value of pitch and roll stick to be adjusted
233
 * to zero (not just to near zero, as per the assumption in rc.c
234
 * about the rc signal. I had values about 50..70 with a Futaba
235
 * R617 receiver.) This calibration is not strictly necessary, but
236
 * for control logic that depends on the exact (non)center position
237
 * of a stick, it may be useful.
238
 */
239
void RC_calibrate(void) {
240
  // Do nothing.
241
}