dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
smoothcontrol.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <math.h>
4 
5 #include "openpilot.h"
6 #include "pios.h"
7 #include "misc_math.h"
8 #include "smoothcontrol.h"
9 
11  // Last known signal value. Needed to detect change.
12  float signal;
13 
14  // Current state of axis.
15  float current;
16 
17  // Amount of differential per step of integration.
18  float differential;
19 
20  // Stores a time-out when to stop predicting. Unit is integrator ticks.
22 
23  // Which conditioning algorithm.
24  uint8_t mode;
25 };
26 
28 
29  // Maximum ticks to integrate. Calculate value from dT and constant. Unit is ticks.
30  uint8_t time_bomb;
31 
32  // Semaphore for cheapskates.
33  bool ringer;
34 
35  // Whole state tick counter
36  uint8_t tick_counter;
37 
38  // Control interval determined by the ringer.
40 
41  // Duty cycle to use.
42  float duty_cycle;
43 
44  // RPY+Thrust.
46 };
47 
48 // Ran on signal change, recalculates the diffs and timeouts for the specific mode.
49 static void smoothcontrol_update(smoothcontrol_state state, struct smoothcontrol_axis_state *axis, const float new_signal)
50 {
51  float signal_diff = new_signal - axis->signal;
52  float cycles = MIN((float)state->control_interval * state->duty_cycle, state->control_interval);
53 
54  switch(axis->mode) {
55  default:
56  // Override any crap values.
57  axis->mode = SMOOTHCONTROL_NONE;
58  case SMOOTHCONTROL_NONE:
59  // Doesn't do anything in the integrator.
60  break;
61 
62  // icee's proposal, creates chamfered steps with signal prediction
64  axis->differential = signal_diff * SMOOTHCONTROL_PREDICTOR_SLOPE / (float)state->control_interval;
65  axis->current = axis->signal + signal_diff * SMOOTHCONTROL_CHAMFER_START;
66  axis->integrator_timeout = (uint8_t)cycles;
67  break;
68 
70  axis->differential = (new_signal - axis->current) / cycles;
71  axis->integrator_timeout = (uint8_t)cycles;
72  break;
73  }
74 
75  axis->signal = new_signal;
76 }
77 
78 // Resets the axis state.
79 void smoothcontrol_reinit(smoothcontrol_state state, uint8_t axis_num, float new_signal)
80 {
81  PIOS_Assert(state);
82 
83  // Prevent integrating when stick scale changes.
84  state->axis[axis_num].differential = 0;
85  state->axis[axis_num].signal = new_signal;
86  state->axis[axis_num].current = new_signal;
87 }
88 
89 // Resets the thrust state.
91 {
92  smoothcontrol_reinit(state, 3, new_signal);
93 }
94 
95 // Sets mode for an axis.
96 void smoothcontrol_set_mode(smoothcontrol_state state, uint8_t axis_num, uint8_t mode, uint8_t duty_cycle)
97 {
98  PIOS_Assert(state && axis_num <= 3);
99  state->duty_cycle = bound_min_max((float)duty_cycle, 0, 100) / 100.0f;
100  smoothcontrol_reinit(state, axis_num, state->axis[axis_num].signal);
101 }
102 
103 // Processes the signal, if internal state allows it.
104 void smoothcontrol_run(smoothcontrol_state state, uint8_t axis_num, float *new_signal)
105 {
106  PIOS_Assert(state && axis_num <= 3);
107 
108  struct smoothcontrol_axis_state *axis = &state->axis[axis_num];
109 
110  // No mode, bypass.
111  if(axis->mode == SMOOTHCONTROL_NONE) return;
112 
113  if(!state->tick_counter) {
114  // Manual control updated, do stuff
115  smoothcontrol_update(state, axis, *new_signal);
116  }
117 
118  if(state->tick_counter < axis->integrator_timeout && state->tick_counter < state->time_bomb) {
119  // Don't fiddle with first value after update.
120  if(state->tick_counter > 0)
121  axis->current += axis->differential;
122  } else {
123  // If we passed the timebomb, force the receiver signal, too.
124  if(state->tick_counter >= state->time_bomb) axis->current = *new_signal;
125  }
126 
127  *new_signal = axis->current;
128 }
129 
130 // Separate handling of thrust.
132 {
133  /* The 0 on zero throttle causes a huge blip when throttling up, so
134  * we need to handle it separately. Also, reset the state, if zero
135  * throttle is requested, so that none of the modes can keep it
136  * non-zero.
137  */
138 
139  if (*new_signal == 0 || *new_signal != *new_signal) {
140  smoothcontrol_reinit(state, 3, 0);
141  } else {
142  bool sign = *new_signal > 0;
143 
144  smoothcontrol_run(state, 3, new_signal);
145 
146  // If prediction undershoots while original signal is positive
147  // bound it to zero.
148 
149  bool new_sign = *new_signal > 0;
150 
151  if (sign != new_sign) {
152  if (sign) {
153  *new_signal = 0.00001f;
154  } else {
155  *new_signal = -0.00001f;
156  }
157  }
158  }
159 }
160 
161 // Advances the tick counters.
163 {
164  PIOS_Assert(state);
165 
166  if(state->tick_counter < 255) state->tick_counter++;
167 
168  // This function is supposed to get called at the end of the stabilization loop.
169  // If MCC rang the ringer meanwhile, ticks will be at zero next loop, as expected.
170  if(state->ringer) {
171  int x = ((int)state->control_interval + (int)state->tick_counter) >> 1;
172  state->control_interval = (uint8_t)MIN(x, 255);
173  state->tick_counter = 0;
174 
175  state->ringer = false;
176  }
177 }
178 
179 // To tell us the dT, to calculate the time bomb for the integrator.
181 {
182  PIOS_Assert(state);
183  state->time_bomb = (uint8_t)(SMOOTHCONTROL_TIMEBOMB / 1000.0f / dT);
184 }
185 
186 // Duh.
188 {
189  PIOS_Assert(state);
190 
191  if(!*state) {
192  *state = PIOS_malloc_no_dma(sizeof(**state));
193  PIOS_Assert(*state);
194  memset(*state, 0, sizeof(**state));
195  }
196 }
197 
199 {
200  PIOS_Assert(state);
201  return &state->ringer;
202 }
void smoothcontrol_set_mode(smoothcontrol_state state, uint8_t axis_num, uint8_t mode, uint8_t duty_cycle)
Definition: smoothcontrol.c:96
Main PiOS header to include all the compiled in PiOS options.
#define SMOOTHCONTROL_PREDICTOR_SLOPE
Definition: smoothcontrol.h:12
#define sign(x)
This is but one definition of sign(.)
Definition: misc_math.h:44
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
void smoothcontrol_update_dT(smoothcontrol_state state, float dT)
struct smoothcontrol_axis_state axis[4]
Definition: smoothcontrol.c:45
#define SMOOTHCONTROL_CHAMFER_START
Definition: smoothcontrol.h:15
void smoothcontrol_reinit_thrust(smoothcontrol_state state, float new_signal)
Definition: smoothcontrol.c:90
void smoothcontrol_next(smoothcontrol_state state)
void smoothcontrol_initialize(smoothcontrol_state *state)
float bound_min_max(float val, float min, float max)
Bound input value between min and max.
Definition: misc_math.c:38
enum channel_mode mode
Definition: pios_servo.c:58
static void smoothcontrol_update(smoothcontrol_state state, struct smoothcontrol_axis_state *axis, const float new_signal)
Definition: smoothcontrol.c:49
#define SMOOTHCONTROL_TIMEBOMB
Definition: smoothcontrol.h:6
tuple f
Definition: px_mkfw.py:81
#define MIN(a, b)
Definition: misc_math.h:41
bool * smoothcontrol_get_ringer(smoothcontrol_state state)
Includes PiOS and core architecture components.
void smoothcontrol_run_thrust(smoothcontrol_state state, float *new_signal)
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void smoothcontrol_run(smoothcontrol_state state, uint8_t axis_num, float *new_signal)
void smoothcontrol_reinit(smoothcontrol_state state, uint8_t axis_num, float new_signal)
Definition: smoothcontrol.c:79
enum arena_state state