Rev 2048 | Rev 2051 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2048 | Rev 2049 | ||
---|---|---|---|
1 | #include <stdlib.h> |
1 | #include <stdlib.h> |
2 | #include "controlMixer.h" |
2 | #include "controlMixer.h" |
3 | #include "rc.h" |
3 | #include "rc.h" |
4 | #include "heightControl.h" |
4 | #include "heightControl.h" |
5 | #include "attitudeControl.h" |
5 | #include "attitudeControl.h" |
6 | #include "externalControl.h" |
6 | #include "externalControl.h" |
7 | #include "compassControl.h" |
7 | #include "compassControl.h" |
8 | #include "naviControl.h" |
8 | #include "naviControl.h" |
9 | #include "configuration.h" |
9 | #include "configuration.h" |
10 | #include "attitude.h" |
10 | #include "attitude.h" |
11 | #include "commands.h" |
11 | #include "commands.h" |
12 | #include "output.h" |
12 | #include "output.h" |
13 | 13 | ||
14 | // uint16_t maxControl[2] = { 0, 0 }; |
14 | // uint16_t maxControl[2] = { 0, 0 }; |
15 | uint16_t controlActivity = 0; |
15 | uint16_t controlActivity = 0; |
16 | int16_t controls[4] = { 0, 0, 0, 0 }; |
16 | int16_t controls[4] = { 0, 0, 0, 0 }; |
17 | 17 | ||
18 | // Internal variables for reading commands made with an R/C stick. |
18 | // Internal variables for reading commands made with an R/C stick. |
19 | uint8_t lastCommand = COMMAND_NONE; |
19 | uint8_t lastCommand = COMMAND_NONE; |
20 | uint8_t lastArgument; |
20 | uint8_t lastArgument; |
21 | 21 | ||
22 | uint8_t isCommandRepeated = 0; |
22 | uint8_t isCommandRepeated = 0; |
23 | uint8_t controlMixer_didReceiveSignal = 0; |
23 | uint8_t controlMixer_didReceiveSignal = 0; |
24 | 24 | ||
25 | /* |
25 | /* |
26 | * This could be expanded to take arguments from ohter sources than the RC |
26 | * This could be expanded to take arguments from ohter sources than the RC |
27 | * (read: Custom MK RC project) |
27 | * (read: Custom MK RC project) |
28 | */ |
28 | */ |
29 | uint8_t controlMixer_getArgument(void) { |
29 | uint8_t controlMixer_getArgument(void) { |
30 | return lastArgument; |
30 | return lastArgument; |
31 | } |
31 | } |
32 | 32 | ||
33 | /* |
33 | /* |
34 | * This could be expanded to take calibrate / start / stop commands from ohter sources |
34 | * This could be expanded to take calibrate / start / stop commands from ohter sources |
35 | * than the R/C (read: Custom MK R/C project) |
35 | * than the R/C (read: Custom MK R/C project) |
36 | */ |
36 | */ |
37 | uint8_t controlMixer_getCommand(void) { |
37 | uint8_t controlMixer_getCommand(void) { |
38 | return lastCommand; |
38 | return lastCommand; |
39 | } |
39 | } |
40 | 40 | ||
41 | uint8_t controlMixer_isCommandRepeated(void) { |
41 | uint8_t controlMixer_isCommandRepeated(void) { |
42 | return isCommandRepeated; |
42 | return isCommandRepeated; |
43 | } |
43 | } |
44 | 44 | ||
45 | void controlMixer_setNeutral() { |
45 | void controlMixer_setNeutral() { |
46 | for (uint8_t i=0; i<VARIABLE_COUNT; i++) { |
46 | for (uint8_t i=0; i<VARIABLE_COUNT; i++) { |
47 | variables[i] = 0; |
47 | variables[i] = 0; |
48 | } |
48 | } |
49 | EC_setNeutral(); |
49 | EC_setNeutral(); |
50 | HC_setGround(); |
50 | HC_setGround(); |
51 | } |
51 | } |
52 | 52 | ||
53 | /* |
53 | /* |
54 | * Set the potientiometer values to the momentary values of the respective R/C channels. |
54 | * Set the potientiometer values to the momentary values of the respective R/C channels. |
55 | * No slew rate limitation. |
55 | * No slew rate limitation. |
56 | */ |
56 | */ |
57 | void controlMixer_initVariables(void) { |
57 | void controlMixer_initVariables(void) { |
58 | uint8_t i; |
58 | uint8_t i; |
59 | for (i=0; i < VARIABLE_COUNT; i++) { |
59 | for (i=0; i < VARIABLE_COUNT; i++) { |
60 | variables[i] = RC_getVariable(i); |
60 | variables[i] = RC_getVariable(i); |
61 | } |
61 | } |
62 | } |
62 | } |
63 | 63 | ||
64 | /* |
64 | /* |
65 | * Update potentiometer values with limited slew rate. Could be made faster if desired. |
65 | * Update potentiometer values with limited slew rate. Could be made faster if desired. |
66 | * TODO: It assumes R/C as source. Not necessarily true. |
66 | * TODO: It assumes R/C as source. Not necessarily true. |
67 | */ |
67 | */ |
68 | void controlMixer_updateVariables(void) { |
68 | void controlMixer_updateVariables(void) { |
69 | uint8_t i; |
69 | uint8_t i; |
70 | int16_t targetvalue; |
70 | int16_t targetvalue; |
71 | for (i=0; i < VARIABLE_COUNT; i++) { |
71 | for (i=0; i < VARIABLE_COUNT; i++) { |
72 | targetvalue = RC_getVariable(i); |
72 | targetvalue = RC_getVariable(i); |
73 | if (targetvalue < 0) |
73 | if (targetvalue < 0) |
74 | targetvalue = 0; |
74 | targetvalue = 0; |
75 | if (variables[i] < targetvalue && variables[i] < 255) |
75 | if (variables[i] < targetvalue && variables[i] < 255) |
76 | variables[i]++; |
76 | variables[i]++; |
77 | else if (variables[i] > 0 && variables[i] > targetvalue) |
77 | else if (variables[i] > 0 && variables[i] > targetvalue) |
78 | variables[i]--; |
78 | variables[i]--; |
79 | } |
79 | } |
80 | } |
80 | } |
81 | 81 | ||
82 | uint8_t controlMixer_getSignalQuality(void) { |
82 | uint8_t controlMixer_getSignalQuality(void) { |
83 | uint8_t rcQ = RC_getSignalQuality(); |
83 | uint8_t rcQ = RC_getSignalQuality(); |
84 | uint8_t ecQ = EC_getSignalQuality(); |
84 | uint8_t ecQ = EC_getSignalQuality(); |
85 | 85 | ||
86 | // This needs not be the only correct solution... |
86 | // This needs not be the only correct solution... |
87 | return rcQ > ecQ ? rcQ : ecQ; |
87 | return rcQ > ecQ ? rcQ : ecQ; |
88 | } |
88 | } |
89 | 89 | ||
90 | void updateControlAndMeasureControlActivity(uint8_t index, int16_t newValue) { |
90 | void updateControlAndMeasureControlActivity(uint8_t index, int16_t newValue) { |
91 | int16_t tmp = controls[index]; |
91 | int16_t tmp = controls[index]; |
92 | controls[index] = newValue; |
92 | controls[index] = newValue; |
93 | 93 | ||
94 | tmp -= newValue; |
94 | tmp -= newValue; |
95 | tmp /= 2; |
95 | tmp /= 2; |
96 | tmp = tmp * tmp; |
96 | tmp = tmp * tmp; |
97 | // tmp += (newValue >= 0) ? newValue : -newValue; |
97 | // tmp += (newValue >= 0) ? newValue : -newValue; |
98 | /* |
98 | /* |
99 | if (controlActivity + (uint16_t)tmp >= controlActivity) |
99 | if (controlActivity + (uint16_t)tmp >= controlActivity) |
100 | controlActivity += tmp; |
100 | controlActivity += tmp; |
101 | else controlActivity = 0xffff; |
101 | else controlActivity = 0xffff; |
102 | */ |
102 | */ |
103 | if (controlActivity + (uint16_t)tmp < 32768) |
103 | if (controlActivity + (uint16_t)tmp < 32768) |
104 | controlActivity += tmp; |
104 | controlActivity += tmp; |
105 | } |
105 | } |
106 | 106 | ||
107 | #define CADAMPING 10 |
107 | #define CADAMPING 10 |
108 | void dampenControlActivity(void) { |
108 | void dampenControlActivity(void) { |
109 | uint32_t tmp = controlActivity; |
109 | uint32_t tmp = controlActivity; |
110 | tmp *= ((1<<CADAMPING)-1); |
110 | tmp *= ((1<<CADAMPING)-1); |
111 | tmp >>= CADAMPING; |
111 | tmp >>= CADAMPING; |
112 | controlActivity = tmp; |
112 | controlActivity = tmp; |
113 | } |
113 | } |
114 | 114 | ||
115 | /* |
115 | /* |
116 | * Update the variables indicating stick position from the sum of R/C, GPS and external control |
116 | * Update the variables indicating stick position from the sum of R/C, GPS and external control |
117 | * and whatever other controls we invented in the meantime... |
117 | * and whatever other controls we invented in the meantime... |
118 | * Update variables. |
118 | * Update variables. |
119 | * Decode commands but do not execute them. |
119 | * Decode commands but do not execute them. |
120 | */ |
120 | */ |
121 | int16_t tempPRTY[4]; |
121 | int16_t tempPRTY[4]; |
122 | 122 | ||
123 | void controlMixer_periodicTask(void) { |
123 | void controlMixer_periodicTask(void) { |
- | 124 | // Decode commands. |
|
- | 125 | uint8_t rcCommand = (RC_getSignalQuality() >= SIGNAL_OK) ? RC_getCommand() |
|
- | 126 | : COMMAND_NONE; |
|
124 | // calculate Stick inputs by rc channels (P) and changing of rc channels (D) |
127 | uint8_t ecCommand = (EC_getSignalQuality() >= SIGNAL_OK) ? EC_getCommand() |
- | 128 | : COMMAND_NONE; |
|
- | 129 | ||
- | 130 | // Update variables ("potis"). |
|
- | 131 | if (controlMixer_getSignalQuality() >= SIGNAL_GOOD) { |
|
- | 132 | controlMixer_updateVariables(); |
|
- | 133 | controlMixer_didReceiveSignal = 1; |
|
125 | // TODO: If no signal --> zero. |
134 | } else { // Signal is not OK |
- | 135 | // Could handle switch to emergency flight here. |
|
- | 136 | // throttle is handled elsewhere. |
|
- | 137 | } |
|
- | 138 | ||
- | 139 | if (rcCommand != COMMAND_NONE) { |
|
- | 140 | isCommandRepeated = (lastCommand == rcCommand); |
|
- | 141 | lastCommand = rcCommand; |
|
- | 142 | lastArgument = RC_getArgument(); |
|
- | 143 | } else if (ecCommand != COMMAND_NONE) { |
|
- | 144 | isCommandRepeated = (lastCommand == ecCommand); |
|
- | 145 | lastCommand = ecCommand; |
|
- | 146 | lastArgument = EC_getArgument(); |
|
- | 147 | } else { |
|
- | 148 | // Both sources have no command, or one or both are out. |
|
- | 149 | // Just set to false. There is no reason to check if the none-command was repeated anyway. |
|
126 | // HC_periodicTask(); |
150 | isCommandRepeated = 0; |
- | 151 | lastCommand = COMMAND_NONE; |
|
- | 152 | } |
|
127 | 153 | ||
128 | // This will init the values (not just add to them). |
154 | // This will init the values (not just add to them). |
129 | RC_periodicTaskAndPRTY(tempPRTY); |
155 | RC_periodicTaskAndPRTY(tempPRTY); |
130 | 156 | ||
131 | // Add external control to RC |
157 | // Add external control to RC |
132 | EC_periodicTaskAndPRTY(tempPRTY); |
158 | EC_periodicTaskAndPRTY(tempPRTY); |
133 | 159 | ||
134 | // Add navigations control to RC and external control. |
160 | // Add navigations control to RC and external control. |
135 | navigation_periodicTaskAndPRTY(tempPRTY); |
161 | navigation_periodicTaskAndPRTY(tempPRTY); |
136 | 162 | ||
137 | // Add compass control (could also have been before navi, they are independent) |
163 | // Add compass control (could also have been before navi, they are independent) |
138 | CC_periodicTaskAndPRTY(tempPRTY); |
164 | CC_periodicTaskAndPRTY(tempPRTY); |
139 | 165 | ||
140 | // Add height control (could also have been before navi and/or compass, they are independent) |
166 | // Add height control (could also have been before navi and/or compass, they are independent) |
141 | HC_periodicTaskAndPRTY(tempPRTY); |
167 | HC_periodicTaskAndPRTY(tempPRTY); |
142 | 168 | ||
143 | // Add attitude control (could also have been before navi and/or compass, they are independent) |
169 | // Add attitude control (could also have been before navi and/or compass, they are independent) |
144 | AC_getPRTY(tempPRTY); |
170 | AC_getPRTY(tempPRTY); |
145 | 171 | ||
146 | // Commit results to global variable and also measure control activity. |
172 | // Commit results to global variable and also measure control activity. |
147 | updateControlAndMeasureControlActivity(CONTROL_PITCH, tempPRTY[CONTROL_PITCH]); |
173 | updateControlAndMeasureControlActivity(CONTROL_PITCH, tempPRTY[CONTROL_PITCH]); |
148 | updateControlAndMeasureControlActivity(CONTROL_ROLL, tempPRTY[CONTROL_ROLL]); |
174 | updateControlAndMeasureControlActivity(CONTROL_ROLL, tempPRTY[CONTROL_ROLL]); |
149 | updateControlAndMeasureControlActivity(CONTROL_YAW, tempPRTY[CONTROL_YAW]); |
175 | updateControlAndMeasureControlActivity(CONTROL_YAW, tempPRTY[CONTROL_YAW]); |
150 | dampenControlActivity(); |
176 | dampenControlActivity(); |
151 | 177 | ||
152 | debugOut.analog[17] = controlActivity/10; |
178 | debugOut.analog[17] = controlActivity/10; |
153 | - | ||
154 | // Update variables ("potis"). |
- | |
155 | if (controlMixer_getSignalQuality() >= SIGNAL_GOOD) { |
- | |
156 | controlMixer_updateVariables(); |
- | |
157 | controlMixer_didReceiveSignal = 1; |
- | |
158 | } else { // Signal is not OK |
- | |
159 | // Could handle switch to emergency flight here. |
- | |
160 | // throttle is handled elsewhere. |
- | |
161 | } |
- | |
162 | 179 | ||
163 | // We can safely do this even with a bad signal - the variables will not have been updated then. |
180 | // We can safely do this even with a bad signal - the variables will not have been updated then. |
164 | configuration_applyVariablesToParams(); |
181 | configuration_applyVariablesToParams(); |
165 | 182 | ||
166 | // part1a end. |
183 | // part1a end. |
167 | 184 | ||
168 | /* This is not really necessary with the dead-band feature on all sticks (see rc.c) |
185 | /* This is not really necessary with the dead-band feature on all sticks (see rc.c) |
169 | if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) { |
186 | if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) { |
170 | if (controlYaw > 2) controlYaw-= 2; |
187 | if (controlYaw > 2) controlYaw-= 2; |
171 | else if (controlYaw< -2) controlYaw += 2; |
188 | else if (controlYaw< -2) controlYaw += 2; |
172 | else controlYaw = 0; |
189 | else controlYaw = 0; |
173 | } |
190 | } |
174 | */ |
191 | */ |
175 | 192 | ||
176 | /* |
193 | /* |
177 | * Record maxima. Predecessor of the control activity stuff. |
194 | * Record maxima. Predecessor of the control activity stuff. |
178 | for (axis = PITCH; axis <= ROLL; axis++) { |
195 | for (axis = PITCH; axis <= ROLL; axis++) { |
179 | if (abs(control[axis] / CONTROL_SCALING) > maxControl[axis]) { |
196 | if (abs(control[axis] / CONTROL_SCALING) > maxControl[axis]) { |
180 | maxControl[axis] = abs(control[axis]) / CONTROL_SCALING; |
197 | maxControl[axis] = abs(control[axis]) / CONTROL_SCALING; |
181 | if (maxControl[axis] > 100) |
198 | if (maxControl[axis] > 100) |
182 | maxControl[axis] = 100; |
199 | maxControl[axis] = 100; |
183 | } else if (maxControl[axis]) |
200 | } else if (maxControl[axis]) |
184 | maxControl[axis]--; |
201 | maxControl[axis]--; |
185 | } |
202 | } |
186 | */ |
203 | */ |
187 | - | ||
188 | // Decode commands. |
- | |
189 | uint8_t rcCommand = (RC_getSignalQuality() >= SIGNAL_OK) ? RC_getCommand() |
- | |
190 | : COMMAND_NONE; |
- | |
191 | uint8_t ecCommand = (EC_getSignalQuality() >= SIGNAL_OK) ? EC_getCommand() |
- | |
192 | : COMMAND_NONE; |
- | |
193 | - | ||
194 | if (rcCommand != COMMAND_NONE) { |
- | |
195 | isCommandRepeated = (lastCommand == rcCommand); |
- | |
196 | lastCommand = rcCommand; |
- | |
197 | lastArgument = RC_getArgument(); |
- | |
198 | } else if (ecCommand != COMMAND_NONE) { |
- | |
199 | isCommandRepeated = (lastCommand == ecCommand); |
- | |
200 | lastCommand = ecCommand; |
- | |
201 | lastArgument = EC_getArgument(); |
- | |
202 | } else { |
- | |
203 | // Both sources have no command, or one or both are out. |
- | |
204 | // Just set to false. There is no reason to check if the none-command was repeated anyway. |
- | |
205 | isCommandRepeated = 0; |
- | |
206 | lastCommand = COMMAND_NONE; |
- | |
207 | } |
- | |
208 | } |
204 | } |
209 | 205 |