Subversion Repositories FlightCtrl

Rev

Rev 2160 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1968 - 1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
1962 - 4
 
1968 - 5
#include "rc.h"
2189 - 6
//#include "controlMixer.h"
1968 - 7
#include "configuration.h"
8
#include "commands.h"
2189 - 9
#include "definitions.h"
1968 - 10
 
2048 - 11
// The channel array is 0-based!
2189 - 12
volatile int16_t PPM_in[MAX_CONTROLCHANNELS];
13
volatile int16_t PPM_diff[MAX_CONTROLCHANNELS];
14
volatile uint16_t RC_buffer[MAX_CONTROLCHANNELS];
15
volatile uint8_t inBfrPnt;
2160 - 16
 
2026 - 17
volatile uint8_t RCQuality;
2189 - 18
uint8_t lastRCCommand;
19
uint8_t commandTimer;
1968 - 20
 
2189 - 21
#define TIME(s) ((int16_t)(((F_CPU/8000)*(float)s + 0.5f)))
2160 - 22
 
1968 - 23
/***************************************************************
24
 *  16bit timer 1 is used to decode the PPM-Signal            
25
 ***************************************************************/
26
void RC_Init(void) {
27
  uint8_t sreg = SREG;
28
 
29
  // disable all interrupts before reconfiguration
30
  cli();
31
 
32
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
33
  DDRD &= ~(1<<6);
34
  PORTD |= (1<<PORTD6);
35
 
36
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
37
  // set as output
38
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
39
  // low level
40
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
41
 
42
  // PD3 can't be used if 2nd UART is activated
43
  // because TXD1 is at that port
44
  if (CPUType != ATMEGA644P) {
45
    DDRD |= (1<<PORTD3);
46
    PORTD &= ~(1<<PORTD3);
47
  }
48
 
49
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
50
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
2189 - 51
  // Set clock source to SYSCLK/8 (bit: CS12=0, CS11=1, CS10=1)
52
  // Enable input capture noise canceler (bit: ICNC1=1)
53
  // Therefore the counter increments at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
1968 - 54
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
2160 - 55
  TCCR1A &= ~((1<<COM1A1)| (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10));
56
  TCCR1B &= ~((1<<WGM13) | (1<<WGM12)  | (1<<CS12));
2189 - 57
  TCCR1B |= (1<<CS11)    | (1<<ICNC1);
2160 - 58
  TCCR1C &= ~((1<<FOC1A) | (1<<FOC1B));
59
 
60
  if (channelMap.RCPolarity) {
61
    TCCR1B |= (1<<ICES1);
62
  } else {
63
    TCCR1B &= ~(1<<ICES1);
64
  }
65
 
1968 - 66
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
67
 
68
  // Timer/Counter1 Interrupt Mask Register
69
  // Enable Input Capture Interrupt (bit: ICIE1=1)
70
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
71
  // Enable Overflow Interrupt (bit: TOIE1=0)
72
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
73
  TIMSK1 |= (1<<ICIE1);
2019 - 74
  RCQuality = 0;
1968 - 75
  SREG = sreg;
76
}
77
 
2160 - 78
/*
79
 * This new and much faster interrupt handler should reduce servo jolts.
80
 */
81
ISR(TIMER1_CAPT_vect) {
82
  static uint16_t oldICR1 = 0;
83
  uint16_t signal = (uint16_t)ICR1 - oldICR1;
84
  oldICR1 = ICR1;
85
  //sync gap? (3.5 ms < signal < 25.6 ms)
86
  if (signal > TIME(3.5)) {
87
        inBfrPnt = 0;
2189 - 88
  } else if (inBfrPnt<MAX_CONTROLCHANNELS) {
2160 - 89
        RC_buffer[inBfrPnt++] = signal;
90
        if (RCQuality <= 200-4) RCQuality+=4; else RCQuality = 200;
91
  }
92
}
93
 
1968 - 94
/********************************************************************/
95
/*         Every time a positive edge is detected at PD6            */
96
/********************************************************************/
97
/*                               t-Frame
98
    <----------------------------------------------------------------------->
99
     ____   ______   _____   ________                ______    sync gap      ____
100
    |    | |      | |     | |        |              |      |                |
101
    |    | |      | |     | |        |              |      |                |
102
 ___|    |_|      |_|     |_|        |_.............|      |________________|
103
    <-----><-------><------><-----------            <------>                <---
104
 t0       t1      t2       t4                     tn                     t0
105
 
1962 - 106
 The PPM-Frame length is 22.5 ms.
107
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
108
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
109
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
110
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
111
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
112
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
113
 the syncronization gap.
114
 */
115
 
2160 - 116
void RC_process(void) {
117
  if (RCQuality) RCQuality--;
2189 - 118
  for (uint8_t channel=0; channel<MAX_CONTROLCHANNELS; channel++) {
2160 - 119
        uint16_t signal = RC_buffer[channel];
120
        if (signal != 0) {
121
          RC_buffer[channel] = 0; // reset to flag value already used.
122
      if ((signal >= TIME(0.8)) && (signal < TIME(2.2))) {
2189 - 123
        signal -= TIME(1.5) /*  + channelMap.HWTrim */;
2160 - 124
        PPM_diff[channel] = signal - PPM_in[channel];
125
        PPM_in[channel] = signal;
1962 - 126
      }
127
    }
128
  }
129
}
130
 
131
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
132
#define RCDiff(dimension) PPM_diff[channelMap.channels[dimension]]
2189 - 133
#define COMMAND_THRESHOLD TIME(0.35f)
1962 - 134
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
135
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
136
 
137
// Internal.
138
uint8_t RC_getStickCommand(void) {
139
  if (RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
140
    // vertical is up
141
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
142
      return COMMAND_GYROCAL;
143
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
144
      return COMMAND_ACCCAL;
145
    return COMMAND_NONE;
146
  } else if (RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
147
    // vertical is down
148
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
149
      return COMMAND_STOP;
150
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
151
      return COMMAND_START;
152
    return COMMAND_NONE;
153
  }
154
  // vertical is around center
155
  return COMMAND_NONE;
156
}
157
 
158
/*
2048 - 159
 * Get Pitch, Roll, Throttle, Yaw values
1962 - 160
 */
2189 - 161
void RC_periodicTaskAndRPTY(int16_t* RPTY) {
1962 - 162
  int16_t tmp1, tmp2;
2160 - 163
  RC_process();
2019 - 164
  if (RCQuality) {
165
    RCQuality--;
2189 - 166
    RPTY[CONTROL_ROLL]      = ((RCChannel(CH_ROLL) * staticParams.stickP) >> 3) + RCDiff(CH_ROLL) * staticParams.stickD;
167
    RPTY[CONTROL_PITCH]     = ((RCChannel(CH_PITCH) * staticParams.stickP) >> 3) + RCDiff(CH_PITCH) * staticParams.stickD;
168
    int16_t throttle        = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE) * staticParams.stickThrottleD + TIME(0.4);
2053 - 169
    // Negative throttle values are taken as zero.
170
    if (throttle > 0)
2189 - 171
      RPTY[CONTROL_THROTTLE]  = throttle;
172
    else
173
      RPTY[CONTROL_THROTTLE]  = 0;
174
 
175
    tmp1 = RCChannel(CH_YAW); // - RCDiff(CH_YAW);
2048 - 176
    // exponential stick sensitivity in yawing rate
2189 - 177
    // 
178
    tmp2 = ((int32_t)staticParams.stickYawP * (int32_t)tmp1 * abs(tmp1)) >> 14; // expo  y = ax + bx^2
179
    tmp2 += (staticParams.stickYawP * tmp1) >> 3;
180
 
181
    RPTY[CONTROL_YAW] = (/*(RCChannel(CH_YAW) * staticParams.stickYawP) >> 3*/ tmp2);
2048 - 182
 
1962 - 183
    uint8_t command = RC_getStickCommand();
2189 - 184
 
1962 - 185
    if (lastRCCommand == command) {
186
      // Keep timer from overrunning.
187
      if (commandTimer < COMMAND_TIMER)
188
        commandTimer++;
189
    } else {
190
      // There was a change.
191
      lastRCCommand = command;
192
      commandTimer = 0;
193
    }
2053 - 194
  } // if RCQuality is no good, we just do nothing.
1962 - 195
}
196
 
197
/*
198
 * Get other channel value
199
 */
200
int16_t RC_getVariable(uint8_t varNum) {
201
  if (varNum < 4)
202
    // 0th variable is 5th channel (1-based) etc.
2189 - 203
    return (RCChannel(varNum + CH_VARIABLES) >> 3) + VARIABLES_OFFSET;
1962 - 204
  /*
205
   * Let's just say:
1986 - 206
   * The RC variable i is hardwired to channel i, i>=4
1962 - 207
   */
2189 - 208
  return (PPM_in[varNum] >> 3) + VARIABLES_OFFSET;
1962 - 209
}
210
 
211
uint8_t RC_getSignalQuality(void) {
2019 - 212
  if (RCQuality >= 160)
1962 - 213
    return SIGNAL_GOOD;
2019 - 214
  if (RCQuality >= 140)
1962 - 215
    return SIGNAL_OK;
2019 - 216
  if (RCQuality >= 120)
1962 - 217
    return SIGNAL_BAD;
218
  return SIGNAL_LOST;
219
}
220
 
221
/*
222
 * To should fired only when the right stick is in the center position.
223
 * This will cause the value of pitch and roll stick to be adjusted
224
 * to zero (not just to near zero, as per the assumption in rc.c
225
 * about the rc signal. I had values about 50..70 with a Futaba
226
 * R617 receiver.) This calibration is not strictly necessary, but
227
 * for control logic that depends on the exact (non)center position
228
 * of a stick, it may be useful.
229
 */
230
void RC_calibrate(void) {
231
  // Do nothing.
232
}
233
 
234
/*
235
 if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
236
 // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
237
 stickOffsetPitch = stickOffsetRoll = 0;
238
 } else {
239
 stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
240
 stickOffsetRoll = RCChannel(CH_ROLL)   * staticParams.StickP;
241
 }
242
 }
243
 */
244
 
245
uint8_t RC_getCommand(void) {
246
  if (commandTimer == COMMAND_TIMER) {
247
    // Stick has been held long enough; command committed.
248
    return lastRCCommand;
249
  }
250
  // Not yet sure what the command is.
251
  return COMMAND_NONE;
252
}
253
 
254
/*
255
 * Command arguments on R/C:
256
 * 2--3--4
257
 * |     |  +
258
 * 1  0  5  ^ 0
259
 * |     |  |  
260
 * 8--7--6
261
 *    
262
 * + <--
263
 *    0
264
 *
265
 * Not in any of these positions: 0
266
 */
267
 
2189 - 268
#define ARGUMENT_THRESHOLD TIME(0.35f)
1962 - 269
#define ARGUMENT_CHANNEL_VERTICAL CH_PITCH
270
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
271
 
272
uint8_t RC_getArgument(void) {
273
  if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
274
    // vertical is up
275
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
276
      return 2;
277
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
278
      return 4;
279
    return 3;
280
  } else if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
281
    // vertical is down
282
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
283
      return 8;
284
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
285
      return 6;
286
    return 7;
287
  } else {
288
    // vertical is around center
289
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
290
      return 1;
291
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
292
      return 5;
293
    return 0;
294
  }
295
}
296
 
2052 - 297
#ifdef USE_MK3MAG
1962 - 298
/*
2048 - 299
 * For each time the stick is pulled, returns true.
300
 */
1962 - 301
uint8_t RC_testCompassCalState(void) {
2048 - 302
  static uint8_t stickPulled = 1;
1962 - 303
  // if pitch is centered or top set stick to zero
304
  if (RCChannel(CH_PITCH) > -20)
2048 - 305
    stickPulled = 0;
1962 - 306
  // if pitch is down trigger to next cal state
2048 - 307
  if ((RCChannel(CH_PITCH) < -70) && !stickPulled) {
308
    stickPulled = 1;
1962 - 309
    return 1;
310
  }
311
  return 0;
312
}
2052 - 313
#endif
314
 
1962 - 315
/*
316
 * Abstract controls are not used at the moment.
317
 t_control rc_control = {
318
 RC_getPitch,
319
 RC_getRoll,
320
 RC_getYaw,
321
 RC_getThrottle,
322
 RC_getSignalQuality,
323
 RC_calibrate
324
 };
325
 */