Subversion Repositories FlightCtrl

Rev

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 "configuration.h"
57
 
58
volatile int16_t PPM_in[15]; //PPM24 supports 12 channels per frame
59
volatile int16_t PPM_diff[15];
60
volatile uint8_t NewPpmData = 1;
61
volatile int16_t RC_Quality = 0;
62
int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
63
 
64
/***************************************************************/
65
/*  16bit timer 1 is used to decode the PPM-Signal            */
66
/***************************************************************/
67
void RC_Init (void) {
68
        uint8_t sreg = SREG;
69
 
70
        // disable all interrupts before reconfiguration
71
        cli();
72
 
73
        // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
74
        DDRD &= ~(1<<DDD6);
75
        PORTD |= (1<<PORTD6);
76
 
77
        // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
78
        // set as output
79
        DDRD |= /*(1<<DDD5)|*/(1<<DDD4);
80
        // low level
81
        PORTD &= ~(/*(1<<PORTD5)|*/(1<<PORTD4));
82
 
83
        // PD3 can't be used if 2nd UART is activated
84
        // because TXD1 is at that port
85
        if(CPUType != ATMEGA644P) {
86
          DDRD |= (1<<PORTD3);
87
          PORTD &= ~(1<<PORTD3);
88
        }
89
 
90
        // Timer/Counter1 Control Register A, B, C
91
 
92
        // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
93
        // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
94
        // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
95
        // Enable input capture noise cancler (bit: ICNC1=1)
96
        // Trigger on positive edge of the input capture pin (bit: ICES1=1),
97
        // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
98
    // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
99
        TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
100
        TCCR1B &= ~((1<<WGM13)|(1<<WGM12)|(1<<CS12));
101
        TCCR1B |= (1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1);
102
        TCCR1C &= ~((1<<FOC1A)|(1<<FOC1B));
103
 
104
        // Timer/Counter1 Interrupt Mask Register
105
 
106
        // Enable Input Capture Interrupt (bit: ICIE1=1)
107
        // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
108
        // Enable Overflow Interrupt (bit: TOIE1=0)
109
        TIMSK1 &= ~((1<<OCIE1B)|(1<<OCIE1A)|(1<<TOIE1));
110
    TIMSK1 |= (1<<ICIE1);
111
 
112
    RC_Quality = 0;
113
 
114
    SREG = sreg;
115
}
116
 
117
 
118
/********************************************************************/
119
/*         Every time a positive edge is detected at PD6            */
120
/********************************************************************/
121
/*                               t-Frame
122
       <----------------------------------------------------------------------->
123
         ____   ______   _____   ________                ______    sync gap      ____
124
        |    | |      | |     | |        |              |      |                |
125
        |    | |      | |     | |        |              |      |                |
126
     ___|    |_|      |_|     |_|        |_.............|      |________________|
127
        <-----><-------><------><-------->              <------>                <---
128
          t0       t1      t2       t4                     tn                     t0
129
 
130
The PPM-Frame length is 22.5 ms.
131
Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
132
The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
133
The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
134
The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
135
The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
136
The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
137
the syncronization gap.
138
*/
139
ISR(TIMER1_CAPT_vect) // typical rate of 1 ms to 2 ms
140
{
141
  int16_t signal = 0, tmp;
142
  static int16_t index;
143
  static uint16_t oldICR1 = 0;
144
 
145
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
146
  // at the time the edge was detected
147
 
148
  // calculate the time delay to the previous event time which is stored in oldICR1
149
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
150
  // implicit handles a timer overflow 65535 -> 0 the right way.
151
  signal = (uint16_t) ICR1 - oldICR1;
152
  oldICR1 = ICR1;
153
 
154
  //sync gap? (3.52 ms < signal < 25.6 ms)
155
  if((signal > 1100) && (signal < 8000))
156
    {
157
      // if a sync gap happens and there where at least 4 channels decoded before
158
      // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
159
      if(index >= 4)
160
        {
161
          NewPpmData = 0;  // Null means NewData for the first 4 channels
162
        }
163
      // synchronize channel index
164
      index = 1;
165
    }
166
  else // within the PPM frame
167
    {
168
      if(index < 14) // PPM24 supports 12 channels
169
        {
170
          // check for valid signal length (0.8 ms < signal < 2.1984 ms)
171
          // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
172
          if((signal > 250) && (signal < 687))
173
            {
174
              // shift signal to zero symmetric range  -154 to 159
175
              signal -= 466; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
176
              // check for stable signal
177
              if(abs(signal - PPM_in[index]) < 6) {
178
                if(RC_Quality < 200) RC_Quality +=10;
179
                else RC_Quality = 200;
180
              }
181
              // calculate exponential history for signal
182
              tmp = (3 * (PPM_in[index]) + signal) / 4;
183
              if(tmp > signal+1) tmp--; else
184
                if(tmp < signal-1) tmp++;
185
              // calculate signal difference on good signal level
186
              if(RC_Quality >= 195)  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[ParamSet.ChannelAssignment[dimension]] * ParamSet.StickP)
205
#define RCDiff(dimension) (PPM_diff[ParamSet.ChannelAssignment[dimension]] * ParamSet.StickD)
206
// To start with, we don't attempt to normalize.
207
//#define rc_normalize(stick) (stick * STICK_RANGE / NORMAL_RANGE_COUNTS)
208
#define RCNormalize(stick) stick
209
 
210
/* Get the pitch input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
211
int16_t RC_getPitch (void) {
212
  return RCNormalize(RCChannel(CH_PITCH) - stickOffsetPitch + RCDiff(CH_PITCH));
213
}
214
 
215
/* Get the roll input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
216
int16_t RC_getRoll (void) {
217
  return RCNormalize(RCChannel(CH_ROLL) - stickOffsetRoll + RCDiff(CH_ROLL));
218
}
219
 
220
/* Get the yaw input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
221
int16_t RC_getYaw (void) {
222
  return RCNormalize(RCChannel(CH_YAW) + RCDiff(CH_YAW));
223
}
224
 
225
/* Get the throttle input in the nominal range [0, THROTTLE_RANGE]. */
226
uint16_t RC_getThrottle(void) {
227
// TODO: Some D term would actually be nice - at least for my acro style.
228
  // return (RcChannel(CH_THROTTLE) + NORMAL_RANGE_COUNTS) * THROTTLE_RANGE / MILLISECOND_COUNTS_1;
229
  return RcChannel(CH_THROTTLE);
230
}
231
 
232
uint16_t RC_getVariable(uint8_t channel) {
233
  return RCChannel(CH_POTS + channel) + POT_OFFSET;
234
}
235
 
236
uint8_t RC_getSignalQuality(void) {
237
  if (RC_Quality >= 160)
238
    return SIGNAL_EXCELLENT;
239
  if (RC_Quality >= 140)
240
    return SIGNAL_OK;
241
  if (RC_Quality >= 120)
242
    return SIGNAL_BAD;
243
  return SIGNAL_LOST;
244
}
245
 
246
/*
247
 * To should fired only when the right stick is in the center position.
248
 * This will cause the value of pitch and roll stick to be adjusted
249
 * to zero (not just to near zero, as per the assumption in rc.c
250
 * about the rc signal. I had values about 50..70 with a Futaba
251
 * R617 receiver.) This calibration is not strictly necessary, but
252
 * for control logic that depends on the exact (non)center position
253
 * of a stick, it may be useful.
254
 */
255
void RC_calibrate(void) {
256
  stickOffsetPitch += stickPitch;
257
  stickOffsetRoll += stickRoll;
258
}
259
 
260
#define COMMAND_THRESHOLD 85
261
uint8_t RC_getCommand(void) {
262
  if(RCChannel(CH_THROTTLE) > COMMAND_THRESHOLD) {
263
    // throttle is up
264
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
265
      return STICK_COMMAND_GYROCAL;
266
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
267
      return STICK_COMMAND_ACCCAL;
268
    return STICK_COMMAND_UNDEF;
269
  } else if(RCChannel(CH_THROTTLE) < -COMMAND_THRESHOLD) {
270
    // pitch is down
271
    if(RCChannel(CH_YAW) > COMMAND_THRESHOLD)
272
      return STICK_COMMAND_STOP;
273
    if(RCChannel(CH_YAW) < -COMMAND_THRESHOLD)
274
      return STICK_COMMAND_START;
275
    return STICK_COMMAND_UNDEF;
276
  } else {
277
    // pitch is around center
278
    return STICK_COMMAND_UNDEF;
279
  }
280
}
281
 
282
/*
283
 * Command arguments on R/C:
284
 * 2--3--4
285
 * |     |  +
286
 * 1  9  5  ^ 0
287
 * |     |  |  
288
 * 8--7--6
289
 *    
290
 * + <--
291
 *    0
292
 *
293
 * Not in any of these positions: 0
294
 */
295
#define ARGUMENT_THRESHOLD 70
296
uint8_t RC_getArgument(void) {
297
  if(RCChannel(CH_PITCH) > ARGUMENT_THRESHOLD) {
298
    // pitch is up
299
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
300
      return 2;
301
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
302
      return 4;
303
    return 3;
304
  } else if(RCChannel(CH_PITCH) < -ARGUMENT_THRESHOLD) {
305
    // pitch is down
306
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
307
      return 8;
308
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
309
      return 6;
310
    return 7;
311
  } else {
312
    // pitch is around center
313
    if(RCChannel(CH_ROLL) > ARGUMENT_THRESHOLD)
314
      return 1;
315
    if(RCChannel(CH_ROLL) < -ARGUMENT_THRESHOLD)
316
      return 5;
317
    return 9;
318
  }
319
}
320
 
321
 
322
/*
323
 * Abstract controls not used at the moment.
324
t_control rc_control = {
325
  RC_getPitch,
326
  RC_getRoll,
327
  RC_getYaw,
328
  RC_getThrottle,
329
  RC_getSignalQuality,
330
  RC_calibrate
331
};
332
*/