Subversion Repositories FlightCtrl

Rev

Rev 1796 | Rev 1868 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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