2c527780c7bf9ecafe8d67709144f6ed8ec82c7b
[aversive.git] / projects / microb2010 / mainboard / strat_base.c
1 /*  
2  *  Copyright Droids Corporation, Microb Technology (2009)
3  * 
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Revision : $Id: strat_base.c,v 1.8 2009-11-08 17:24:33 zer0 Exp $
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26
27 #include <aversive/pgmspace.h>
28 #include <aversive/wait.h>
29 #include <aversive/error.h>
30
31 #include <ax12.h>
32 #include <uart.h>
33 #include <pwm_ng.h>
34 #include <clock_time.h>
35 #include <spi.h>
36
37 #include <pid.h>
38 #include <quadramp.h>
39 #include <control_system_manager.h>
40 #include <trajectory_manager.h>
41 #include <trajectory_manager_utils.h>
42 #include <vect_base.h>
43 #include <lines.h>
44 #include <polygon.h>
45 #include <obstacle_avoidance.h>
46 #include <blocking_detection_manager.h>
47 #include <robot_system.h>
48 #include <position_manager.h>
49
50 #include <rdline.h>
51 #include <parse.h>
52
53 #include "../common/i2c_commands.h"
54
55 #include "main.h"
56 #include "cmdline.h"
57 #include "strat_utils.h"
58 #include "strat_base.h"
59 #include "strat.h"
60 #include "sensor.h"
61 #include "i2c_protocol.h"
62
63 /* true if we want to interrupt a trajectory */
64 static uint8_t traj_intr=0;
65
66 /* filled when a END_OBSTACLE is returned */
67 struct opponent_obstacle opponent_obstacle;
68
69 /* asked speed */
70 static volatile int16_t strat_speed_a = SPEED_DIST_FAST;
71 static volatile int16_t strat_speed_d = SPEED_ANGLE_FAST;
72 static volatile uint16_t strat_limit_speed_a = 0; /* no limit */
73 static volatile uint16_t strat_limit_speed_d = 0;
74
75 static volatile uint8_t strat_limit_speed_enabled = 1;
76
77
78 /* Strings that match the end traj cause */
79 /* /!\ keep it sync with stat_base.h */
80 const char *err_tab []= {
81         "END_TRAJ",
82         "END_BLOCKING",
83         "END_NEAR",
84         "END_OBSTACLE",
85         "END_ERROR",
86         "END_INTR",
87         "END_TIMER",
88         "END_RESERVED",
89 };
90
91 /* return string from end traj type num */
92 const char *get_err(uint8_t err)
93 {
94         uint8_t i;
95         if (err == 0)
96                 return "SUCCESS";
97         for (i=0 ; i<8; i++) {
98                 if (err & (1 <<i))
99                         return err_tab[i];
100         }
101         return "END_UNKNOWN";
102 }
103
104 void strat_hardstop(void) 
105 {
106         trajectory_hardstop(&mainboard.traj);
107         pid_reset(&mainboard.angle.pid);
108         pid_reset(&mainboard.distance.pid);
109         bd_reset(&mainboard.angle.bd);
110         bd_reset(&mainboard.distance.bd);
111
112         while ((ABS(mainboard.speed_d) > 200) ||
113                (ABS(mainboard.speed_a) > 200))
114
115         trajectory_hardstop(&mainboard.traj);
116         pid_reset(&mainboard.angle.pid);
117         pid_reset(&mainboard.distance.pid);
118         bd_reset(&mainboard.angle.bd);
119         bd_reset(&mainboard.distance.bd);
120 }
121
122 /* go to an x,y point without checking for obstacle or blocking. It
123  * should be used for very small dist only. Return END_TRAJ if we
124  * reach destination, or END_BLOCKING if the robot blocked more than 3
125  * times. */
126 uint8_t strat_goto_xy_force(int16_t x, int16_t y)
127 {
128         uint8_t i, err;
129
130         for (i=0; i<3; i++) {
131                 trajectory_goto_xy_abs(&mainboard.traj, x, y);
132                 err = wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
133                 if (TRAJ_SUCCESS(err))
134                         return END_TRAJ;
135                 if (err == END_BLOCKING) {
136                         time_wait_ms(500);
137                         strat_hardstop();
138                 }
139         }
140         return END_BLOCKING;
141 }
142
143 /* reset position */ 
144 void strat_reset_pos(int16_t x, int16_t y, int16_t a)
145 {
146         int16_t posx = position_get_x_s16(&mainboard.pos);
147         int16_t posy = position_get_y_s16(&mainboard.pos);
148         int16_t posa = position_get_a_deg_s16(&mainboard.pos);
149
150         if (x == DO_NOT_SET_POS)
151                 x = posx;
152         if (y == DO_NOT_SET_POS)
153                 y = posy;
154         if (a == DO_NOT_SET_POS)
155                 a = posa;
156
157         DEBUG(E_USER_STRAT, "reset pos (%s%s%s)",
158               x == DO_NOT_SET_POS ? "" : "x",
159               y == DO_NOT_SET_POS ? "" : "y",
160               a == DO_NOT_SET_POS ? "" : "a");
161         position_set(&mainboard.pos, x, y, a);
162         DEBUG(E_USER_STRAT, "pos resetted", __FUNCTION__);
163 }
164
165 /* 
166  * decrease gain on angle PID, and go forward until we reach the
167  * border.
168  */
169 uint8_t strat_calib(int16_t dist, uint8_t flags)
170 {
171         int32_t p = pid_get_gain_P(&mainboard.angle.pid);
172         int32_t i = pid_get_gain_I(&mainboard.angle.pid);
173         int32_t d = pid_get_gain_D(&mainboard.angle.pid);
174         uint8_t err;
175
176         pid_set_gains(&mainboard.angle.pid, 150, 0, 2000);
177         trajectory_d_rel(&mainboard.traj, dist);
178         err = wait_traj_end(flags);
179         pid_set_gains(&mainboard.angle.pid, p, i, d);
180         return err;
181 }
182
183 static void strat_update_traj_speed(void)
184 {
185         uint16_t d, a;
186
187         d = strat_speed_d;
188         if (strat_limit_speed_d && d > strat_limit_speed_d)
189                 d = strat_limit_speed_d;
190         a = strat_speed_a;
191         if (strat_limit_speed_a && a > strat_limit_speed_a)
192                 a = strat_limit_speed_a;
193         
194         trajectory_set_speed(&mainboard.traj, d, a);
195 }
196
197 void strat_set_speed(uint16_t d, uint16_t a)
198 {
199         uint8_t flags;
200         IRQ_LOCK(flags);
201         strat_speed_d = d;
202         strat_speed_a = a;
203         strat_update_traj_speed();
204         IRQ_UNLOCK(flags);
205 }
206
207 void strat_get_speed(uint16_t *d, uint16_t *a)
208 {
209         uint8_t flags;
210         IRQ_LOCK(flags);
211         *d = strat_speed_d;
212         *a = strat_speed_a;
213         IRQ_UNLOCK(flags);
214 }
215
216 void strat_limit_speed_enable(void)
217 {
218         strat_limit_speed_enabled = 1;
219 }
220
221 void strat_limit_speed_disable(void)
222 {
223         strat_limit_speed_enabled = 0;
224 }
225
226 /* called periodically */
227 void strat_limit_speed(void)
228 {
229         uint16_t lim_d = 0, lim_a = 0;
230         int16_t opp_d, opp_a;
231
232         if (strat_limit_speed_enabled == 0)
233                 goto update;
234
235         if (get_opponent_da(&opp_d, &opp_a) != 0)
236                 goto update;
237
238         if (opp_d < 500) {
239                 if (mainboard.speed_d > 0 && (opp_a > 290 || opp_a < 70)) {
240                         lim_d = SPEED_DIST_VERY_SLOW;
241                         lim_a = SPEED_ANGLE_VERY_SLOW;
242                 }
243                 else if (mainboard.speed_d < 0 && (opp_a < 250 && opp_a > 110)) {
244                         lim_d = SPEED_DIST_VERY_SLOW;
245                         lim_a = SPEED_ANGLE_VERY_SLOW;
246                 }
247                 else {
248                         lim_d = SPEED_DIST_SLOW;
249                         lim_a = SPEED_ANGLE_VERY_SLOW;
250                 }
251         }
252         else if (opp_d < 800) {
253                 if (mainboard.speed_d > 0 && (opp_a > 290 || opp_a < 70)) {
254                         lim_d = SPEED_DIST_SLOW;
255                         lim_a = SPEED_ANGLE_SLOW;
256                 }
257                 else if (mainboard.speed_d < 0 && (opp_a < 250 && opp_a > 110)) {
258                         lim_d = SPEED_DIST_SLOW;
259                         lim_a = SPEED_ANGLE_SLOW;
260                 }
261         }
262
263  update:
264         if (lim_d != strat_limit_speed_d ||
265             lim_a != strat_limit_speed_a) {
266                 strat_limit_speed_d = lim_d;
267                 strat_limit_speed_a = lim_a;
268                 DEBUG(E_USER_STRAT, "new speed limit da=%d,%d", lim_d, lim_a);
269                 strat_update_traj_speed();
270         }
271 }
272
273 /* start the strat */
274 void strat_start(void)
275
276         int8_t i;
277         uint8_t err;
278
279         strat_preinit();
280
281         /* if start sw not plugged */
282         if (sensor_get(S_START_SWITCH)) {
283                 printf_P(PSTR("No start switch, press a key or plug it\r\n"));
284
285                 /* while start sw not plugged */
286                 while (sensor_get(S_START_SWITCH)) {
287                         if (! cmdline_keypressed())
288                                 continue;
289
290                         for (i=3; i>0; i--) {
291                                 printf_P(PSTR("%d\r\n"), i);
292                                 time_wait_ms(1000);
293                         }
294                         break;
295                 }
296         }
297         
298         /* if start sw plugged */
299         if (!sensor_get(S_START_SWITCH)) {
300                 printf_P(PSTR("Ready, unplug start switch to start\r\n"));
301                 /* while start sw plugged */
302                 while (!sensor_get(S_START_SWITCH));
303         }
304
305         strat_init();
306         err = strat_main();
307         NOTICE(E_USER_STRAT, "Finished !! returned %s", get_err(err));
308         strat_exit();
309 }
310
311 /* return true if we have to brake due to an obstacle */
312 uint8_t strat_obstacle(void)
313 {
314         int16_t x_rel, y_rel;
315         int16_t opp_x, opp_y, opp_d, opp_a;
316
317         /* too slow */
318         if (ABS(mainboard.speed_d) < 150)
319                 return 0;
320
321         /* no opponent detected */
322         if (get_opponent_xyda(&opp_x, &opp_y,
323                               &opp_d, &opp_a))
324                 return 0;
325
326         /* save obstacle position */
327         opponent_obstacle.x = opp_x;
328         opponent_obstacle.y = opp_y;
329         opponent_obstacle.d = opp_d;
330         opponent_obstacle.a = opp_a;
331
332         /* sensor are temporarily disabled */
333         if (sensor_obstacle_is_disabled())
334                 return 0;
335
336         /* relative position */
337         x_rel = cos(RAD(opp_a)) * (double)opp_d;
338         y_rel = sin(RAD(opp_a)) * (double)opp_d;
339
340         /* opponent too far */
341         if (opp_d > 600)
342                 return 0;
343
344         /* opponent is in front of us */
345         if (mainboard.speed_d > 0 && (opp_a > 325 || opp_a < 35)) {
346                 DEBUG(E_USER_STRAT, "opponent front d=%d, a=%d "
347                       "xrel=%d yrel=%d (speed_d=%d)", 
348                       opp_d, opp_a, x_rel, y_rel, mainboard.speed_d);
349                 sensor_obstacle_disable();
350                 return 1;
351         }
352         /* opponent is behind us */
353         if (mainboard.speed_d < 0 && (opp_a < 215 && opp_a > 145)) {
354                 DEBUG(E_USER_STRAT, "opponent behind d=%d, a=%d xrel=%d yrel=%d", 
355                       opp_d, opp_a, x_rel, y_rel);
356                 sensor_obstacle_disable();
357                 return 1;
358         }
359
360         return 0;
361 }
362
363 void interrupt_traj(void)
364 {
365         traj_intr = 1;
366 }
367
368 void interrupt_traj_reset(void)
369 {
370         traj_intr = 0;
371 }
372
373 uint8_t test_traj_end(uint8_t why)
374
375         uint16_t cur_timer;
376         point_t robot_pt;
377
378         robot_pt.x = position_get_x_s16(&mainboard.pos);
379         robot_pt.y = position_get_y_s16(&mainboard.pos);
380
381         /* trigger an event at 3 sec before the end of the match if we
382          * have balls in the barrel */
383         cur_timer = time_get_s();
384
385         if ((mainboard.flags & DO_TIMER) && (why & END_TIMER)) {
386                 /* end of match */
387                 if (cur_timer >= MATCH_TIME)
388                         return END_TIMER;
389         }
390
391         if ((why & END_INTR) && traj_intr) {
392                 interrupt_traj_reset();         
393                 return END_INTR;
394         }
395
396         if ((why & END_TRAJ) && trajectory_finished(&mainboard.traj))
397                 return END_TRAJ;
398         
399         /* we are near the destination point (depends on current
400          * speed) AND the robot is in the area bounding box. */
401         if (why & END_NEAR) {
402                 int16_t d_near = 100;   
403                 
404                 if (mainboard.speed_d > 2000)
405                         d_near = 150;
406                 
407                 if (trajectory_in_window(&mainboard.traj, d_near, RAD(5.0)) &&
408                     is_in_boundingbox(&robot_pt))
409                         return END_NEAR;
410         }
411         
412         if ((why & END_BLOCKING) && bd_get(&mainboard.angle.bd)) {
413                 strat_hardstop();
414                 return END_BLOCKING;
415         }
416
417         if ((why & END_BLOCKING) && bd_get(&mainboard.distance.bd)) {
418                 strat_hardstop();
419                 return END_BLOCKING;
420         }
421
422         if ((why & END_OBSTACLE) && strat_obstacle()) {
423                 strat_hardstop();
424                 return END_OBSTACLE;
425         }
426
427         return 0;
428 }
429
430 uint8_t __wait_traj_end_debug(uint8_t why, uint16_t line)
431 {
432         uint8_t ret = 0;
433         int16_t opp_x, opp_y, opp_d, opp_a;
434
435         while (ret == 0)
436                 ret = test_traj_end(why);
437
438         if (ret == END_OBSTACLE) {
439                 if (get_opponent_xyda(&opp_x, &opp_y,
440                                       &opp_d, &opp_a) == 0)
441                         DEBUG(E_USER_STRAT, "Got %s at line %d"
442                               " xy=(%d,%d) da=(%d,%d)", get_err(ret),
443                               line, opp_x, opp_y, opp_d, opp_a);
444         }
445         else {
446                 DEBUG(E_USER_STRAT, "Got %s at line %d", 
447                       get_err(ret), line);
448         }
449         return ret;
450 }