Subversion Repositories FlightCtrl

Rev

Rev 1634 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1612 dongfang 1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// + Copyright (c) 04.2007 Holger Buss
3
// + Nur für den privaten Gebrauch
4
// + www.MikroKopter.com
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
7
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
8
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
11
// + Verkauf von Luftbildaufnahmen, usw.
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
14
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
17
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt werden
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
21
// + Benutzung auf eigene Gefahr
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
25
// + mit unserer Zustimmung zulässig
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
30
// + this list of conditions and the following disclaimer.
31
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
32
// +     from this software without specific prior written permission.
33
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
34
// +     for non-commercial use (directly or indirectly)
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
36
// +     with our written permission
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
38
// +     clearly linked as origin
39
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
40
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
// +  POSSIBILITY OF SUCH DAMAGE.
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51
#include <stdlib.h>
52
#include <avr/io.h>
53
#include <avr/interrupt.h>
54
 
55
#include "rc.h"
56
#include "controlMixer.h"
57
#include "configuration.h"
58
 
59
// The channel array is 1-based. The 0th entry is not used.
60
volatile int16_t PPM_in[MAX_CHANNELS];
61
volatile int16_t PPM_diff[MAX_CHANNELS];
62
volatile uint8_t NewPpmData = 1;
63
volatile int16_t RC_Quality = 0;
64
int16_t RC_PRTY[4];
65
 
66
int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
67
 
68
/***************************************************************
69
 *  16bit timer 1 is used to decode the PPM-Signal            
70
 ***************************************************************/
71
void RC_Init (void) {
72
  uint8_t sreg = SREG;
73
 
74
  // disable all interrupts before reconfiguration
75
  cli();
76
 
77
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
78
  DDRD &= ~(1<<DDD6);
79
  PORTD |= (1<<PORTD6);
80
 
81
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
82
  // set as output
83
  DDRD |= /*(1<<DDD5)|*/(1<<DDD4);
84
  // low level
85
  PORTD &= ~(/*(1<<PORTD5)|*/(1<<PORTD4));
86
 
87
  // PD3 can't be used if 2nd UART is activated
88
  // because TXD1 is at that port
89
  if(CPUType != ATMEGA644P) {
90
    DDRD |= (1<<PORTD3);
91
    PORTD &= ~(1<<PORTD3);
92
  }
93
 
94
  // Timer/Counter1 Control Register A, B, C
95
 
96
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
97
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
98
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
99
  // Enable input capture noise cancler (bit: ICNC1=1)
100
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
101
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
102
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
103
  TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
104
  TCCR1B &= ~((1<<WGM13)|(1<<WGM12)|(1<<CS12));
105
  TCCR1B |= (1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1);
106
  TCCR1C &= ~((1<<FOC1A)|(1<<FOC1B));
107
 
108
  // Timer/Counter1 Interrupt Mask Register
109
 
110
  // Enable Input Capture Interrupt (bit: ICIE1=1)
111
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
112
  // Enable Overflow Interrupt (bit: TOIE1=0)
113
  TIMSK1 &= ~((1<<OCIE1B)|(1<<OCIE1A)|(1<<TOIE1));
114
  TIMSK1 |= (1<<ICIE1);
115
 
116
  RC_Quality = 0;
117
 
118
  SREG = sreg;
119
}
120
 
121
 
122
/********************************************************************/
123
/*         Every time a positive edge is detected at PD6            */
124
/********************************************************************/
125
/*                               t-Frame
126
                                 <----------------------------------------------------------------------->
127
                                 ____   ______   _____   ________                ______    sync gap      ____
128
                                 |    | |      | |     | |        |              |      |                |
129
                                 |    | |      | |     | |        |              |      |                |
130
                                 ___|    |_|      |_|     |_|        |_.............|      |________________|
131
                                 <-----><-------><------><-------->              <------>                <---
132
                                 t0       t1      t2       t4                     tn                     t0
133
 
134
                                 The PPM-Frame length is 22.5 ms.
135
                                 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
136
                                 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
137
                                 The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
138
                                 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
139
                                 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
140
                                 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
141
                                 the syncronization gap.
142
*/
143
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
144
  int16_t signal = 0, tmp;
145
  static int16_t index;
146
  static uint16_t oldICR1 = 0;
147
 
148
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
149
  // at the time the edge was detected
150
 
151
  // calculate the time delay to the previous event time which is stored in oldICR1
152
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
153
  // implicit handles a timer overflow 65535 -> 0 the right way.
154
  signal = (uint16_t) ICR1 - oldICR1;
155
  oldICR1 = ICR1;
156
 
157
  //sync gap? (3.52 ms < signal < 25.6 ms)
158
  if((signal > 1100) && (signal < 8000)) {
159
    // if a sync gap happens and there where at least 4 channels decoded before
160
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
161
    if(index >= 4) {
162
      NewPpmData = 0;  // Null means NewData for the first 4 channels
163
    }
164
    // synchronize channel index
165
    index = 1;
166
  } else { // within the PPM frame
167
    if(index < MAX_CHANNELS-1) // PPM24 supports 12 channels
168
      {
169
        // check for valid signal length (0.8 ms < signal < 2.1984 ms)
170
        // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
171
        if((signal > 250) && (signal < 687))
172
          {
173
            // shift signal to zero symmetric range  -154 to 159
174
            signal -= 466; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
175
            // check for stable signal
176
            if(abs(signal - PPM_in[index]) < 6) {
177
              if(RC_Quality < 200) RC_Quality +=10;
178
              else RC_Quality = 200;
179
            }
180
            // calculate exponential history for signal
181
            tmp = (3 * PPM_in[index] + signal) / 4;
182
            if(tmp > signal + 1) tmp--; else
183
              if(tmp < signal-1) tmp++;
184
            // calculate signal difference on good signal level
185
            if(RC_Quality >= 195)  
186
              PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
187
            else PPM_diff[index] = 0;
188
            PPM_in[index] = tmp; // update channel value
189
          }
190
        index++; // next channel
191
        // demux sum signal for channels 5 to 7 to J3, J4, J5
192
        // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
193
        // channels are usually available at the receiver anyway.
194
        // if(index == 5) J3HIGH; else J3LOW;
195
        // if(index == 6) J4HIGH; else J4LOW;
196
        // if(CPUType != ATMEGA644P) // not used as TXD1
197
        //  {
198
        //    if(index == 7) J5HIGH; else J5LOW;
199
        //  }
200
      }
201
  }
202
}
203
 
204
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
205
#define RCDiff(dimension) PPM_diff[staticParams.ChannelAssignment[dimension]]
206
 
207
/*
208
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
209
 */
210
void RC_update() {
211
  int16_t tmp1, tmp2;
212
  if(RC_Quality) {
213
    RC_Quality--;
214
    if (NewPpmData-- == 0) {
215
      RC_PRTY[CONTROL_PITCH] = (RCChannel(CH_PITCH) - stickOffsetPitch) * staticParams.StickP + RCDiff(CH_PITCH) * staticParams.StickD;
216
      RC_PRTY[CONTROL_ROLL] = (RCChannel(CH_ROLL) - stickOffsetRoll)   * staticParams.StickP + RCDiff(CH_ROLL)  * staticParams.StickD;
217
      RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + PPM_diff[staticParams.ChannelAssignment[CH_THROTTLE]] * dynamicParams.UserParams[6] + 120;
218
      if (RC_PRTY[CONTROL_THROTTLE] < 0) RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
219
      tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
220
      // exponential stick sensitivity in yawring rate
221
      tmp2 = (int32_t) staticParams.StickYawP * ((int32_t)tmp1 * abs(tmp1)) / 512L; // expo  y = ax + bx^2
222
      tmp2 += (staticParams.StickYawP * tmp1) / 4;
223
      RC_PRTY[CONTROL_YAW] = tmp2;
224
    }
225
  } else { // Bad signal
226
    RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE] = RC_PRTY[CONTROL_YAW] = 0;
227
  }
228
}
229
 
230
/*
231
 * Get Pitch, Roll, Throttle, Yaw values
232
 */
233
int16_t* RC_getPRTY(void) {
234
  return RC_PRTY;
235
}
236
 
237
/*
238
 * Get other channel value
239
 */
240
int16_t RC_getVariable(uint8_t varNum) {
241
  if (varNum < 4)
242
    // 0th variable is 5th channel (1-based) etc.
243
    return RCChannel(varNum + 5);
244
  /*
245
   * Let's just say:
246
   * The RC variable 4 is hardwired to channel 5
247
   * The RC variable 5 is hardwired to channel 6
248
   * The RC variable 6 is hardwired to channel 7
249
   * The RC variable 7 is hardwired to channel 8
250
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
251
   */
252
  return PPM_in[varNum + 1];
253
}
254
 
255
uint8_t RC_getSignalQuality(void) {
256
  if (RC_Quality >= 160)
257
    return SIGNAL_GOOD;
258
  if (RC_Quality >= 140)
259
    return SIGNAL_OK;
260
  if (RC_Quality >= 120)
261
    return SIGNAL_BAD;
262
  return SIGNAL_LOST;
263
}
264
 
265
/*
266
 * To should fired only when the right stick is in the center position.
267
 * This will cause the value of pitch and roll stick to be adjusted
268
 * to zero (not just to near zero, as per the assumption in rc.c
269
 * about the rc signal. I had values about 50..70 with a Futaba
270
 * R617 receiver.) This calibration is not strictly necessary, but
271
 * for control logic that depends on the exact (non)center position
272
 * of a stick, it may be useful.
273
 */
274
void RC_calibrate(void) {
275
  if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
276
    // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
277
    stickOffsetPitch = stickOffsetRoll = 0;
278
  } else {
279
    stickOffsetPitch += RCChannel(CH_PITCH);
280
    stickOffsetRoll += RCChannel(CH_ROLL);
281
  }
282
}
283
 
284
#define COMMAND_THRESHOLD 85
285
uint8_t RC_getCommand(void) {
286
  if(RCChannel(CH_THROTTLE) > COMMAND_THRESHOLD) {
287
    // throttle is up
288
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
289
      return COMMAND_GYROCAL;
290
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
291
      return COMMAND_ACCCAL;
292
    return COMMAND_NONE;
293
  } else if(RCChannel(CH_THROTTLE) < -COMMAND_THRESHOLD) {
294
    // pitch is down
295
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
296
      return COMMAND_STOP;
297
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
298
      return COMMAND_START;
299
    return COMMAND_NONE;
300
  } else {
301
    // pitch is around center
302
    return COMMAND_NONE;
303
  }
304
}
305
 
306
/*
307
 * Command arguments on R/C:
308
 * 2--3--4
309
 * |     |  +
310
 * 1  0  5  ^ 0
311
 * |     |  |  
312
 * 8--7--6
313
 *    
314
 * + <--
315
 *    0
316
 *
317
 * Not in any of these positions: 0
318
 */
319
#define ARGUMENT_THRESHOLD 70
320
uint8_t RC_getArgument(void) {
321
  if(RCChannel(CH_PITCH) > ARGUMENT_THRESHOLD) {
322
    // pitch is up
323
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
324
      return 2;
325
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
326
      return 4;
327
    return 3;
328
  } else if(RCChannel(CH_PITCH) < -ARGUMENT_THRESHOLD) {
329
    // pitch is down
330
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
331
      return 8;
332
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
333
      return 6;
334
    return 7;
335
  } else {
336
    // pitch is around center
337
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
338
      return 1;
339
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
340
      return 5;
341
    return 0;
342
  }
343
}
344
 
345
uint8_t RC_getLooping(uint8_t looping) {
346
  //  static uint8_t looping = 0;
347
 
348
  if(RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_LEFT) {
349
    looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
350
  } else if((looping & LOOPING_LEFT) && RCChannel(CH_ROLL) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
351
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
352
  }
353
 
354
  if(RCChannel(CH_ROLL) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_RIGHT) {
355
    looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
356
  } else if((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
357
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
358
  }
359
 
360
  if(RCChannel(CH_PITCH) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_UP) {
361
    looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
362
  } else if((looping & LOOPING_UP) && RCChannel(CH_PITCH) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
363
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
364
  }
365
 
366
  if(RCChannel(CH_PITCH) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_DOWN) {
367
    looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
368
  } else if((looping & LOOPING_DOWN) && RCChannel(CH_PITCH) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
369
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
370
  }
371
 
372
  return looping;
373
}
374
 
375
/*
376
 * Abstract controls are not used at the moment.
377
 t_control rc_control = {
378
 RC_getPitch,
379
 RC_getRoll,
380
 RC_getYaw,
381
 RC_getThrottle,
382
 RC_getSignalQuality,
383
 RC_calibrate
384
 };
385
*/