RC Pilot
input_manager.c
Go to the documentation of this file.
1 /**
2  * @file input_manager.c
3  */
4 
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <math.h> // for fabs
9 
10 #include <rc/start_stop.h>
11 #include <rc/pthread.h>
12 #include <rc/time.h>
13 #include <rc/dsm.h>
14 #include <rc/math/other.h>
15 
16 #include <input_manager.h>
17 #include <settings.h>
18 #include <rc_pilot_defs.h>
19 #include <thread_defs.h>
20 
21 user_input_t user_input; // extern variable in input_manager.h
22 
23 static pthread_t input_manager_thread;
24 static arm_state_t kill_switch = DISARMED; // raw kill switch on the radio
25 
26 
27 /**
28 * float apply_deadzone(float in, float zone)
29 *
30 * Applies a dead zone to an input stick in. in is supposed to range from -1 to 1
31 * the dead zone is centered around 0. zone specifies the distance from 0 the
32 * zone extends.
33 **/
34 static double __deadzone(double in, double zone)
35 {
36  if(zone<=0.0) return in;
37  if(fabs(in)<=zone) return 0.0;
38  if(in>0.0) return ((in-zone)/(1.0-zone));
39  else return ((in+zone)/(1.0-zone));
40 }
41 
42 
43 /**
44  * @brief blocking function that returns after arming sequence is complete
45  *
46  * @return 0 if successful or already armed, -1 if exiting or problem
47  */
48 static int __wait_for_arming_sequence()
49 {
50  // already armed, just return. Should never do this in normal operation though
51  if(user_input.requested_arm_mode == ARMED) return 0;
52 
53 ARM_SEQUENCE_START:
54  // wait for feedback controller to have started
55  while(fstate.initialized==0){
56  rc_usleep(100000);
57  if(rc_get_state()==EXITING) return 0;
58  }
59  // wait for level
61  rc_usleep(100000);
62  if(rc_get_state()==EXITING) return 0;
63  }
64  // wait for kill switch to be switched to ARMED
65  while(kill_switch==DISARMED){
66  rc_usleep(100000);
67  if(rc_get_state()==EXITING) return 0;
68  }
69  // wait for throttle up
70  while(rc_dsm_ch_normalized(settings.dsm_thr_ch)*settings.dsm_thr_pol < 0.9){
71  rc_usleep(100000);
72  if(rc_get_state()==EXITING) return 0;
73  if(kill_switch==DISARMED) goto ARM_SEQUENCE_START;
74  }
75  // wait for throttle down
76  while(rc_dsm_ch_normalized(settings.dsm_thr_ch)*settings.dsm_thr_pol > -0.9){
77  rc_usleep(100000);
78  if(rc_get_state()==EXITING) return 0;
79  if(kill_switch==DISARMED) goto ARM_SEQUENCE_START;
80  }
81 
82  // final check of kill switch and level before arming
83  if(kill_switch==DISARMED) goto ARM_SEQUENCE_START;
85  goto ARM_SEQUENCE_START;
86  }
87  return 0;
88 }
89 
90 
92 {
93  double new_thr, new_roll, new_pitch, new_yaw, new_mode, new_kill;
94 
95  // Read normalized (+-1) inputs from RC radio stick and multiply by
96  // polarity setting so positive stick means positive setpoint
97  new_thr = rc_dsm_ch_normalized(settings.dsm_thr_ch)*settings.dsm_thr_pol;
98  new_roll = rc_dsm_ch_normalized(settings.dsm_roll_ch)*settings.dsm_roll_pol;
99  new_pitch = rc_dsm_ch_normalized(settings.dsm_pitch_ch)*settings.dsm_pitch_pol;
100  new_yaw = __deadzone(rc_dsm_ch_normalized(settings.dsm_yaw_ch)*settings.dsm_yaw_pol, YAW_DEADZONE);
101  new_mode = rc_dsm_ch_normalized(settings.dsm_mode_ch)*settings.dsm_mode_pol;
102 
103 
104  // kill mode behaviors
105  switch(settings.dsm_kill_mode){
107  new_kill = rc_dsm_ch_normalized(settings.dsm_kill_ch)*settings.dsm_kill_pol;
108  // determine the kill state
109  if(new_kill<=0.1){
110  kill_switch = DISARMED;
111  user_input.requested_arm_mode=DISARMED;
112  }
113  else{
114  kill_switch = ARMED;
115  }
116  break;
117 
119  if(new_thr<=-1.1){
120  kill_switch = DISARMED;
121  user_input.requested_arm_mode=DISARMED;
122  }
123  else kill_switch = ARMED;
124  break;
125 
126  default:
127  fprintf(stderr, "ERROR in input manager, unhandled settings.dsm_kill_mode\n");
128  return;
129  }
130 
131  // saturate the sticks to avoid possible erratic behavior
132  // throttle can drop below -1 so extend the range for thr
133  rc_saturate_double(&new_thr, -1.0, 1.0);
134  rc_saturate_double(&new_roll, -1.0, 1.0);
135  rc_saturate_double(&new_pitch, -1.0, 1.0);
136  rc_saturate_double(&new_yaw, -1.0, 1.0);
137 
138  // pick flight mode
139  switch(settings.num_dsm_modes){
140  case 1:
141  user_input.flight_mode = settings.flight_mode_1;
142  break;
143  case 2:
144  // switch will either range from -1 to 1 or 0 to 1.
145  // in either case it's safe to use +0.5 as the cutoff
146  if(new_mode>0.5) user_input.flight_mode = settings.flight_mode_2;
147  else user_input.flight_mode = settings.flight_mode_1;
148  break;
149  case 3:
150  // 3-position switch will have the positions -1, 0, 1 when
151  // calibrated correctly. checking +- 0.5 is a safe cutoff
152  if(new_mode>0.5) user_input.flight_mode = settings.flight_mode_3;
153  else if(new_mode<-0.5) user_input.flight_mode = settings.flight_mode_1;
154  else user_input.flight_mode = settings.flight_mode_2;
155  break;
156  default:
157  fprintf(stderr,"ERROR, in input_manager, num_dsm_modes must be 1,2 or 3\n");
158  fprintf(stderr,"selecting flight mode 1\n");
159  user_input.flight_mode = settings.flight_mode_1;
160  break;
161  }
162 
163  // fill in sticks
164  if(user_input.requested_arm_mode==ARMED){
165  user_input.thr_stick = new_thr;
166  user_input.roll_stick = new_roll;
167  user_input.pitch_stick = new_pitch;
168  user_input.yaw_stick = new_yaw;
169  user_input.requested_arm_mode = kill_switch;
170  }
171  else{
172  // during arming sequence keep sticks zeroed
173  user_input.thr_stick = 0.0;
174  user_input.roll_stick = 0.0;
175  user_input.pitch_stick = 0.0;
176  user_input.yaw_stick = 0.0;
177  }
178 
179  if(user_input.input_active==0){
180  user_input.input_active=1; // flag that connection has come back online
181  printf("DSM CONNECTION ESTABLISHED\n");
182  }
183  return;
184 
185 }
186 
187 
189 {
190  user_input.thr_stick = 0.0;
191  user_input.roll_stick = 0.0;
192  user_input.pitch_stick = 0.0;
193  user_input.yaw_stick = 0.0;
194  user_input.input_active = 0;
195  kill_switch = DISARMED;
196  user_input.requested_arm_mode=DISARMED;
197  fprintf(stderr, "LOST DSM CONNECTION\n");
198 }
199 
200 
201 void* input_manager(void* ptr)
202 {
203  user_input.initialized = 1;
204  // wait for first packet
205  while(rc_get_state()!=EXITING){
206  if(user_input.input_active) break;
207  rc_usleep(1000000/INPUT_MANAGER_HZ);
208  }
209 
210  // not much to do since the DSM callbacks to most of it. Later some
211  // logic to handle other inputs such as mavlink/bluetooth/wifi
212  while(rc_get_state()!=EXITING){
213  // if the core got disarmed, wait for arming sequence
214  if(user_input.requested_arm_mode == DISARMED){
215  __wait_for_arming_sequence();
216  // user may have pressed the pause button or shut down while waiting
217  // check before continuing
218  if(rc_get_state()!=RUNNING) continue;
219  else{
220  user_input.requested_arm_mode=ARMED;
221  //printf("\n\nDSM ARM REQUEST\n\n");
222  }
223  }
224  // wait
225  rc_usleep(1000000/INPUT_MANAGER_HZ);
226  }
227  return NULL;
228 }
229 
230 
231 
233 {
234  user_input.initialized = 0;
235  int i;
236  // start dsm hardware
237  if(rc_dsm_init()==-1){
238  fprintf(stderr, "ERROR in input_manager_init, failed to initialize dsm\n");
239  return -1;
240  }
241  rc_dsm_set_disconnect_callback(dsm_disconnect_callback);
242  rc_dsm_set_callback(new_dsm_data_callback);
243  // start thread
244  if(rc_pthread_create(&input_manager_thread, &input_manager, NULL,
245  SCHED_FIFO, INPUT_MANAGER_PRI)==-1){
246  fprintf(stderr, "ERROR in input_manager_init, failed to start thread\n");
247  return -1;
248  }
249  // wait for thread to start
250  for(i=0;i<50;i++){
251  if(user_input.initialized) return 0;
252  rc_usleep(50000);
253  }
254  fprintf(stderr, "ERROR in input_manager_init, timeout waiting for thread to start\n");
255  return -1;
256 }
257 
258 
260 {
261  if(user_input.initialized==0){
262  fprintf(stderr, "WARNING in input_manager_cleanup, was never initialized\n");
263  return -1;
264  }
265  // wait for the thread to exit
266  if(rc_pthread_timed_join(input_manager_thread, NULL, INPUT_MANAGER_TOUT)==1){
267  fprintf(stderr,"WARNING: in input_manager_cleanup, thread join timeout\n");
268  return -1;
269  }
270  // stop dsm
271  rc_dsm_cleanup();
272  return 0;
273 }
int dsm_yaw_ch
Definition: settings.h:54
double pitch_stick
positive forward
Definition: input_manager.h:50
feedback_state_t fstate
Definition: feedback.c:30
int dsm_pitch_pol
Definition: settings.h:53
double roll_stick
positive to the right
Definition: input_manager.h:49
void dsm_disconnect_callback(void)
double pitch
current pitch angle (rad)
Definition: feedback.h:43
int initialized
set to 1 after input_manager_init()
Definition: input_manager.h:41
double yaw_stick
positive to the right, CW yaw
Definition: input_manager.h:48
int dsm_roll_pol
Definition: settings.h:51
arm_state_t
constants and parameters
Definition: rc_pilot_defs.h:14
int dsm_kill_ch
Definition: settings.h:59
user_input_t user_input
Definition: input_manager.c:21
double roll
current roll angle (rad)
Definition: feedback.h:41
double thr_stick
positive forward
Definition: input_manager.h:47
int dsm_roll_ch
Definition: settings.h:50
int num_dsm_modes
Definition: settings.h:41
int input_manager_cleanup()
Waits for the input manager thread to exit.
settings_t settings
Definition: settings.c:24
dsm_kill_mode_t dsm_kill_mode
Definition: settings.h:58
flight_mode_t flight_mode
this is the user commanded flight_mode.
Definition: input_manager.h:42
int dsm_pitch_ch
Definition: settings.h:52
int input_active
nonzero indicates some user control is coming in
Definition: input_manager.h:43
int dsm_mode_pol
Definition: settings.h:57
#define ARM_TIP_THRESHOLD
radians from level to allow arming sequence
Definition: rc_pilot_defs.h:20
int dsm_thr_pol
Definition: settings.h:49
#define INPUT_MANAGER_HZ
Definition: thread_defs.h:7
flight_mode_t flight_mode_2
Definition: settings.h:43
#define INPUT_MANAGER_TOUT
Definition: thread_defs.h:9
int initialized
set to 1 after feedback_init()
Definition: feedback.h:31
#define INPUT_MANAGER_PRI
Definition: thread_defs.h:8
void new_dsm_data_callback()
Definition: input_manager.c:91
int input_manager_init()
Starts an input manager thread.
#define YAW_DEADZONE
Definition: rc_pilot_defs.h:37
void * input_manager(void *ptr)
int dsm_thr_ch
Definition: settings.h:48
int dsm_kill_pol
Definition: settings.h:60
arm_state_t requested_arm_mode
set to ARMED after arming sequence is entered.
Definition: input_manager.h:44
int dsm_mode_ch
Definition: settings.h:56
int dsm_yaw_pol
Definition: settings.h:55
flight_mode_t flight_mode_3
Definition: settings.h:44
flight_mode_t flight_mode_1
Definition: settings.h:42