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 "control.h"
53
 
54
#include "rc.h"
55
#include "configuration.h"
56
#include "attitude.h"
57
#include "eeprom.h"
58
#include "flight.h"
59
 
60
#define RCChannel(dimension) (PPM_in[staticParams.ChannelAssignment[dimension]])
61
 
62
uint16_t maxStickPitch = 0, maxStickRoll = 0;
63
int16_t stickPitch = 0, stickRoll = 0, stickYaw = 0, stickThrottle = 0;
64
int16_t GPSStickPitch = 0, GPSStickRoll = 0;
65
int16_t externalStickPitch = 0, externalStickRoll = 0, externalStickYaw = 0, externalHeightValue = -20;
66
 
67
// dongfang's own experiment: Cablibrated sticks.
68
int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
69
 
70
// Looping-or-not flags.
71
uint8_t loopingPitch = 0, loopingRoll = 0;
72
uint8_t loopingLeft = 0, loopingRight = 0, loopingDown = 0, loopingTop = 0;
73
 
74
// Internal variables for reading commands made with an R/S stick.
75
uint8_t lastStickCommand  = STICK_COMMAND_UNDEF;
76
uint8_t stickCommandTimer = 0;
77
 
78
ExternalControl_t externalControl;
79
 
80
/*
81
 * Stick diagram:
82
 * 2--3--4
83
 * |     |  +
84
 * 1  9  5  ^ 0
85
 * |     |  |  
86
 * 8--7--6
87
 *    
88
 * + <--
89
 *    0
90
 *
91
 * Not in any of these positions: 0
92
 */
93
 
94
/*
95
 * The stick most be further from center than this to indicate a settings number (1-5).
96
 */
97
#define STICK_SETTINGSELECTION_THRESHOLD 70
98
 
99
uint8_t control_getLeftRCStickIndex(int16_t thresholdThrottle, int16_t thresholdYaw) {
100
  if(RCChannel(CH_THROTTLE) > thresholdThrottle) {
101
    // throttle is up
102
    if(RCChannel(CH_YAW) > thresholdYaw)
103
      return STICK_COMMAND_GYROCAL;
104
    if(RCChannel(CH_YAW) < -thresholdYaw)
105
      return STICK_COMMAND_ACCCAL;
106
    return STICK_COMMAND_UNDEF;
107
  } else if(RCChannel(CH_THROTTLE) < -thresholdThrottle) {
108
    // pitch is down
109
    if(RCChannel(CH_YAW) > thresholdYaw)
110
      return STICK_COMMAND_STOP;
111
    if(RCChannel(CH_YAW) < -thresholdYaw)
112
      return STICK_COMMAND_START;
113
    return STICK_COMMAND_UNDEF;
114
  } else {
115
    // pitch is around center
116
    return STICK_COMMAND_UNDEF;
117
  }
118
}
119
 
120
uint8_t control_getRightRCStickIndex(void) {
121
  if(RCChannel(CH_PITCH) > STICK_SETTINGSELECTION_THRESHOLD) {
122
    // pitch is up
123
    if(RCChannel(CH_ROLL) > STICK_SETTINGSELECTION_THRESHOLD)
124
      return 2;
125
    if(RCChannel(CH_ROLL) < -STICK_SETTINGSELECTION_THRESHOLD)
126
      return 4;
127
    return 3;
128
  } else if(RCChannel(CH_PITCH) < -STICK_SETTINGSELECTION_THRESHOLD) {
129
    // pitch is down
130
    if(RCChannel(CH_ROLL) > STICK_SETTINGSELECTION_THRESHOLD)
131
      return 8;
132
    if(RCChannel(CH_ROLL) < -STICK_SETTINGSELECTION_THRESHOLD)
133
      return 6;
134
    return 7;
135
  } else {
136
    // pitch is around center
137
    if(RCChannel(CH_ROLL) > STICK_SETTINGSELECTION_THRESHOLD)
138
      return 1;
139
    if(RCChannel(CH_ROLL) < -STICK_SETTINGSELECTION_THRESHOLD)
140
      return 5;
141
    return 9;
142
  }
143
}
144
 
145
/*
146
 * This could be expanded to take calibrate / start / stop commands from ohter sources
147
 * than the R/C (read: Custom MK R/C project)
148
 */
149
void control_senseStickCommands(void) {
150
  uint8_t stickCommandNow = control_getLeftRCStickIndex(85, 85);
151
  if (stickCommandNow != lastStickCommand) {
152
    lastStickCommand = stickCommandNow;
153
    stickCommandTimer = 0;
154
  } else {
155
    if (stickCommandTimer < 201)
156
      stickCommandTimer++;
157
  }
158
}
159
 
160
/*
161
 * This could be expanded to take calibrate / start / stop commands from ohter sources
162
 * than the R/C (read: Custom MK R/C project)
163
 */
164
uint8_t control_getStickCommand(void) {
165
  // If the same command was made 200 times, it's stable.
166
  if (stickCommandTimer >= 200) {
167
    return lastStickCommand;
168
  }
169
  return STICK_COMMAND_UNDEF;
170
}
171
 
172
uint8_t control_isStickCommandRepeated(void) {
173
  return stickCommandTimer > 200 ? 1 : 0;
174
}
175
 
176
/*
177
 * To be fired only when the right stick is in the center position.
178
 * This will cause the value of pitch and roll stick to be adjusted
179
 * to zero (not just to near zero, as per the assumption in rc.c
180
 * about the rc signal. I had values about 50..70 with a Futaba
181
 * R617 receiver.) This calibration is not strictly necessary, but
182
 * for control logic that depends on the exact (non)center position
183
 * of a stick, it may be useful.
184
 */
185
void control_setNeutral(void) {
186
  stickOffsetPitch += stickPitch;
187
  stickOffsetRoll += stickRoll;
188
}
189
 
190
/*
191
 * Set the potientiometer values to the values of the respective R/C channel
192
 * right now. No slew rate limit.
193
 */
194
void control_initPots(void) {
195
  uint8_t i;
196
  for (i=0; i<4; i++) {
197
    pots[i] = RCChannel(CH_POTS + i) + POT_OFFSET;
198
  }
199
  for (i=4; i<8; i++) {
200
    pots[i] = PPM_in[9 + (i-4)] + POT_OFFSET;
201
  }
202
}
203
 
204
/*
205
 * Update potentiometer values with slow slew rate. Could be made faster if desired.
206
 */
207
void control_updatePots(void) {
208
  uint8_t i;
209
  uint16_t targetvalue;
210
  for (i=0; i<8; i++) {
211
    if (i<4)  // configured pots
212
      targetvalue = RCChannel(CH_POTS + i) + POT_OFFSET;
213
    else      // PPM24-Extension
214
      targetvalue = PPM_in[9 + i] + POT_OFFSET;
215
    if (targetvalue < 0) targetvalue = 0;
216
    if (pots[i] < targetvalue && pots[i] < 255) pots[i]++; else if(pots[i] > 0 && pots[i] > targetvalue) pots[i]--;
217
  }
218
}
219
 
220
/*
221
 * Update the variables indicating stick position from the sum of R/C, GPS and external control.
222
 */
223
void control_update(void) {
224
  // calculate Stick inputs by rc channels (P) and changing of rc channels (D)
225
  stickPitch = RCChannel(CH_PITCH) * staticParams.StickP;
226
  // (stick_pitch * 3 + RCChannel(CH_PITCH) * staticParams.StickP) / 4;
227
  stickPitch += PPM_diff[staticParams.ChannelAssignment[CH_PITCH]] * staticParams.StickD;
228
  stickPitch = stickPitch - stickOffsetPitch - GPSStickPitch;
229
 
230
  stickRoll = RCChannel(CH_ROLL) * staticParams.StickP;
231
  // stick_roll = (stick_roll * 3 + RCChannel(CH_ROLL) * staticParams.StickP) / 4;
232
  stickRoll += PPM_diff[staticParams.ChannelAssignment[CH_ROLL]] * staticParams.StickD;
233
  stickRoll = stickRoll - stickOffsetRoll - GPSStickRoll;
234
 
235
  // mapping of yaw
236
  stickYaw = -RCChannel(CH_YAW);
237
  // (range of -2 .. 2 is set to zero, to avoid unwanted yaw trimming on compass correction)
238
  if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE|CFG_GPS_ACTIVE)) {
239
    if (stickYaw > 2) stickYaw-= 2;
240
    else if (stickYaw< -2) stickYaw += 2;
241
    else stickYaw = 0;
242
  }
243
 
244
  // mapping of gas
245
  stickThrottle = RCChannel(CH_THROTTLE) + 120;// shift to positive numbers
246
 
247
  if(externalControl.config & 0x01 && dynamicParams.ExternalControl > 128) {
248
    stickPitch += (int16_t) externalControl.pitch * (int16_t) staticParams.StickP;
249
    stickRoll += (int16_t) externalControl.roll * (int16_t) staticParams.StickP;
250
    stickYaw += externalControl.yaw;
251
    // ExternHeightValue =  (int16_t) ExternControl.Height * (int16_t)staticParams.Height_Gain;
252
    // Dubious: Lowest throttle setting has precedence.
253
    if(externalControl.throttle < stickThrottle) stickThrottle = externalControl.throttle;
254
  }
255
 
256
  if(stickThrottle < 0) stickThrottle = 0;
257
 
258
  if(abs(stickPitch / STICK_GAIN) > maxStickPitch) {
259
    maxStickPitch = abs(stickPitch) / STICK_GAIN;
260
    if(maxStickPitch > 100) maxStickPitch = 100;
261
  }
262
  else if (maxStickPitch) maxStickPitch--;
263
 
264
  if(abs(stickRoll / STICK_GAIN) > maxStickRoll) {
265
    maxStickRoll = abs(stickRoll) / STICK_GAIN;
266
    if(maxStickRoll > 100) maxStickRoll = 100;
267
  }
268
  else if (maxStickRoll) maxStickRoll--;
269
 
270
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
271
  // Looping? Do not consider external or GPS input for this :)
272
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
273
  if((RCChannel(CH_ROLL) > staticParams.LoopThreshold) && staticParams.BitConfig & CFG_LOOP_LEFT)  loopingLeft = 1;
274
  else {
275
    if(loopingLeft) { // Hysteresis
276
      if((RCChannel(CH_ROLL) < (staticParams.LoopThreshold - staticParams.LoopHysteresis))) loopingLeft = 0;
277
    }
278
  }
279
 
280
  if((RCChannel(CH_ROLL) < -staticParams.LoopThreshold) && staticParams.BitConfig & CFG_LOOP_RIGHT) loopingRight = 1;
281
  else {
282
    if(loopingRight) { // Hysteresis
283
      if(RCChannel(CH_ROLL) > -(staticParams.LoopThreshold - staticParams.LoopHysteresis)) loopingRight = 0;
284
    }
285
  }
286
 
287
  if((RCChannel(CH_PITCH) > staticParams.LoopThreshold) && staticParams.BitConfig & CFG_LOOP_UP) loopingTop = 1;
288
  else {
289
    if(loopingTop) { // Hysteresis
290
      if((RCChannel(CH_PITCH) < (staticParams.LoopThreshold - staticParams.LoopHysteresis))) loopingTop = 0;
291
    }
292
  }
293
 
294
  if((RCChannel(CH_PITCH) < -staticParams.LoopThreshold) && staticParams.BitConfig & CFG_LOOP_DOWN) loopingDown = 1;
295
  else {
296
    if(loopingDown) { // Hysteresis
297
      if(RCChannel(CH_PITCH) > -(staticParams.LoopThreshold - staticParams.LoopHysteresis)) loopingDown = 0;
298
    }
299
  }
300
 
301
  if(loopingLeft || loopingRight)  loopingRoll = 1; else loopingRoll = 0;
302
  if(loopingTop  || loopingDown) { loopingPitch = 1; loopingRoll = 0; loopingLeft = 0; loopingRight = 0;} else  loopingPitch = 0;
303
}
304
 
305
void setCompassCalState(void) {
306
  static uint8_t stick = 1;
307
  // if pitch is centered or top set stick to zero
308
  if(RCChannel(CH_PITCH) > -20) stick = 0;
309
  // if pitch is down trigger to next cal state
310
  if((RCChannel(CH_PITCH) < -70) && !stick) {
311
    stick = 1;
312
    compassCalState++;
313
    if(compassCalState < 5) beepNumber(compassCalState);
314
    else beep(1000);
315
  }
316
}
317
 
318
/*
319
 *
320
 */
321
uint8_t control_hasNewRCData(void) {
322
  // return !NewPpmData--;
323
  return (NewPpmData-- == 0) ? 1 : 0;
324
}
325
 
326
void control_performPilotCalibrationCommands(uint8_t stickCommand) {
327
  if (stickCommand == STICK_COMMAND_GYROCAL && !control_isStickCommandRepeated()) {
328
    // Run gyro calibration but do not repeat it.
329
    GRN_OFF;
330
 
331
    // TODO: out of here. Anyway, MKFLAG_MOTOR_RUN is cleared. Not enough?
332
    // isFlying = 0;
333
    // check roll/pitch stick position
334
    // if pitch stick is top or roll stick is left or right --> change parameter setting
335
    // according to roll/pitch stick position
336
 
337
    uint8_t setting = control_getRightRCStickIndex();
338
 
339
    if ((setting > 0 && setting < 6) || setting == 9) {
340
      // Gyro calinbration, with or without selecting a new parameter-set.
341
      if(setting > 0 && setting < 6) {
342
        // A valid parameter-set (1..5) was chosen - use it.
343
        setActiveParamSet(setting);
344
      }
345
      ParamSet_ReadFromEEProm(getActiveParamSet());
346
      attitude_setNeutral();
347
      flight_setNeutral();
348
      if (setting == 9) { // Right stick is centered; calibrate it to zero (hmm strictly does not belong here).
349
        control_setNeutral(); // Calibrate right stick neutral position.
350
      }
351
      beepNumber(getActiveParamSet());
352
    } else if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE) && setting == 7) {
353
      // If right stick is centered and down
354
      compassCalState = 1;
355
      beep(1000);
356
    }
357
  }
358
 
359
  // save the ACC neutral setting to eeprom
360
  else  {
361
    if(stickCommand == STICK_COMMAND_ACCCAL && !control_isStickCommandRepeated()) {
362
      // Run gyro and acc. meter calibration but do not repeat it.
363
      GRN_OFF;
364
      analog_calibrateAcc();
365
      attitude_setNeutral();
366
      flight_setNeutral();
367
      control_setNeutral(); // Calibrate right stick neutral position.
368
      beepNumber(getActiveParamSet());
369
    }
370
  }
371
} // end !MOTOR_RUN condition.