reliability
[aversive.git] / projects / microb2010 / mainboard / robotsim.c
1 /*  
2  *  Copyright Droids Corporation, Microb Technology, Eirbot (2005)
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: main.c,v 1.9.4.5 2007-06-01 09:37:22 zer0 Exp $
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30
31 #include <aversive.h>
32 #include <aversive/error.h>
33
34 #include <timer.h>
35 #include <scheduler.h>
36 #include <time.h>
37
38 #include <ax12.h>
39 #include <pwm_ng.h>
40 #include <pid.h>
41 #include <quadramp.h>
42 #include <control_system_manager.h>
43 #include <trajectory_manager.h>
44 #include <blocking_detection_manager.h>
45 #include <robot_system.h>
46 #include <position_manager.h>
47 #include <trajectory_manager_utils.h>
48
49 #include <parse.h>
50 #include <rdline.h>
51
52 #include "../common/i2c_commands.h"
53 #include "strat.h"
54 #include "strat_utils.h"
55 #include "main.h"
56
57 static int32_t l_pwm, r_pwm;
58 static int32_t l_enc, r_enc;
59
60 static int fdr, fdw;
61 /*
62  * Debug with GDB:
63  *
64  * (gdb) handle SIGUSR1 pass
65  * Signal        Stop   Print   Pass to program Description
66  * SIGUSR1       Yes    Yes     Yes             User defined signal 1
67  * (gdb) handle SIGUSR2 pass
68  * Signal        Stop   Print   Pass to program Description
69  * SIGUSR2       Yes    Yes     Yes             User defined signal 2
70  * (gdb) handle SIGUSR1 noprint
71  * Signal        Stop   Print   Pass to program Description
72  * SIGUSR1       No     No      Yes             User defined signal 1
73  * (gdb) handle SIGUSR2 noprint
74  */
75
76 /* */
77 #define FILTER  98
78 #define FILTER2 (100-FILTER)
79 #define SHIFT   4
80
81 void robotsim_dump(void)
82 {
83         char buf[BUFSIZ];
84         int len;
85         int16_t x, y, a;
86
87         x = position_get_x_s16(&mainboard.pos);
88         y = position_get_y_s16(&mainboard.pos);
89         a = position_get_a_deg_s16(&mainboard.pos);
90 /*      y = COLOR_Y(y); */
91 /*      a = COLOR_A(a); */
92
93         len = snprintf(buf, sizeof(buf), "pos=%d,%d,%d\n",
94                        x, y, a);
95         hostsim_lock();
96         write(fdw, buf, len);
97         hostsim_unlock();
98 }
99
100 static int8_t
101 robotsim_i2c_ballboard_set_mode(struct i2c_cmd_ballboard_set_mode *cmd)
102 {
103         char buf[BUFSIZ];
104         int len;
105
106         ballboard.mode = cmd->mode;
107         len = snprintf(buf, sizeof(buf), "ballboard=%d\n", cmd->mode);
108         if (cmd->mode == I2C_BALLBOARD_MODE_EJECT)
109                 ballboard.ball_count = 0;
110         hostsim_lock();
111         write(fdw, buf, len);
112         hostsim_unlock();
113         return 0;
114 }
115
116 static int8_t
117 robotsim_i2c_cobboard_set_mode(struct i2c_cmd_cobboard_set_mode *cmd)
118 {
119         if (cmd->mode == I2C_COBBOARD_MODE_EJECT)
120                 cobboard.cob_count = 0;
121         return 0;
122 }
123
124 int8_t
125 robotsim_i2c_cobboard_set_spickles(uint8_t side, uint8_t flags)
126 {
127         char buf[BUFSIZ];
128         int len;
129
130         if (side == I2C_LEFT_SIDE) {
131                 if (cobboard.lspickle == flags)
132                         return 0;
133                 else
134                         cobboard.lspickle = flags;
135         }
136         if (side == I2C_RIGHT_SIDE) {
137                 if (cobboard.rspickle == flags)
138                         return 0;
139                 else
140                         cobboard.rspickle = flags;
141         }
142
143         len = snprintf(buf, sizeof(buf), "cobboard=%d,%d\n", side, flags);
144         hostsim_lock();
145         write(fdw, buf, len);
146         hostsim_unlock();
147         return 0;
148 }
149
150 static int8_t
151 robotsim_i2c_ballboard(uint8_t addr, uint8_t *buf, uint8_t size)
152 {
153         void *void_cmd = buf;
154
155         switch (buf[0]) {
156         case I2C_CMD_BALLBOARD_SET_MODE:
157                 {
158                         struct i2c_cmd_ballboard_set_mode *cmd = void_cmd;
159                         robotsim_i2c_ballboard_set_mode(cmd);
160                         break;
161                 }
162
163         default:
164                 break;
165         }
166         return 0;
167 }
168
169 static int8_t
170 robotsim_i2c_cobboard(uint8_t addr, uint8_t *buf, uint8_t size)
171 {
172         void *void_cmd = buf;
173
174         switch (buf[0]) {
175
176         case I2C_CMD_COBBOARD_SET_MODE:
177                 {
178                         struct i2c_cmd_cobboard_set_mode *cmd = void_cmd;
179                         robotsim_i2c_cobboard_set_mode(cmd);
180                         break;
181                 }
182
183         default:
184                 break;
185         }
186         return 0;
187 }
188
189 int8_t
190 robotsim_i2c(uint8_t addr, uint8_t *buf, uint8_t size)
191 {
192         if (addr == I2C_BALLBOARD_ADDR)
193                 return robotsim_i2c_ballboard(addr, buf, size);
194         else if (addr == I2C_COBBOARD_ADDR)
195                 return robotsim_i2c_cobboard(addr, buf, size);
196         return 0;
197 }
198
199 static void beacon_update(void)
200 {
201        uint8_t flags;
202        int16_t oppx, oppy;
203        double oppa, oppd;
204
205        IRQ_LOCK(flags);
206        if (ballboard.opponent_x == I2C_OPPONENT_NOT_THERE) {
207                IRQ_UNLOCK(flags);
208                return;
209        }
210        oppx = ballboard.opponent_x;
211        oppy = ballboard.opponent_y;
212        abs_xy_to_rel_da(oppx, oppy, &oppd, &oppa);
213        ballboard.opponent_a = DEG(oppa);
214        if (ballboard.opponent_a < 0)
215                ballboard.opponent_a += 360;
216        ballboard.opponent_d = oppd;
217        IRQ_UNLOCK(flags);
218 }
219
220 /* must be called periodically */
221 void robotsim_update(void)
222 {
223         static int32_t l_pwm_shift[SHIFT];
224         static int32_t r_pwm_shift[SHIFT];
225         static int32_t l_speed, r_speed;
226         static unsigned i = 0;
227         static unsigned cpt = 0;
228
229         uint8_t flags;
230         int32_t local_l_pwm, local_r_pwm;
231         double x, y, a, a2, d;
232         char cmd[BUFSIZ];
233         int n, pertl = 0, pertr = 0;
234
235         /* corners of the robot */
236         double xfl, yfl; /* front left */
237         double xrl, yrl; /* rear left */
238         double xrr, yrr; /* rear right */
239         double xfr, yfr; /* front right */
240
241         int oppx, oppy;
242         double oppa, oppd;
243
244         beacon_update();
245
246         /* time shift the command */
247         l_pwm_shift[i] = l_pwm;
248         r_pwm_shift[i] = r_pwm;
249         i ++;
250         i %= SHIFT;
251         local_l_pwm = l_pwm_shift[i];
252         local_r_pwm = r_pwm_shift[i];
253
254         /* read command */
255         if (((cpt ++) & 0x7) == 0) {
256                 n = read(fdr, &cmd, BUFSIZ - 1);
257                 if (n < 1)
258                         n = 0;
259                 cmd[n] = 0;
260         }
261
262         /* perturbation */
263         if (cmd[0] == 'l')
264                 pertl = 1;
265         else if (cmd[0] == 'r')
266                 pertr = 1;
267         if (cmd[0] == 'o') {
268                 if (sscanf(cmd, "opp %d %d", &oppx, &oppy) == 2) {
269                         abs_xy_to_rel_da(oppx, oppy, &oppd, &oppa);
270                         IRQ_LOCK(flags);
271                         ballboard.opponent_x = oppx;
272                         ballboard.opponent_y = oppy;
273                         ballboard.opponent_a = DEG(oppa);
274                         if (ballboard.opponent_a < 0)
275                                 ballboard.opponent_a += 360;
276                         ballboard.opponent_d = oppd;
277                         IRQ_UNLOCK(flags);
278                 }
279         }
280
281         x = position_get_x_double(&mainboard.pos);
282         y = position_get_y_double(&mainboard.pos);
283         a = position_get_a_rad_double(&mainboard.pos);
284
285         l_speed = ((l_speed * FILTER) / 100) +
286                 ((local_l_pwm * 1000 * FILTER2)/1000);
287         r_speed = ((r_speed * FILTER) / 100) +
288                 ((local_r_pwm * 1000 * FILTER2)/1000);
289
290         /* basic collision detection */
291         a2 = atan2(ROBOT_WIDTH/2, ROBOT_HALF_LENGTH_REAR);
292         d = norm(ROBOT_WIDTH/2, ROBOT_HALF_LENGTH_REAR);
293
294         xfl = x + cos(a+a2) * d;
295         yfl = y + sin(a+a2) * d;
296         if (!is_in_area(xfl, yfl, 0) && l_speed > 0)
297                 l_speed = 0;
298
299         xrl = x + cos(a+M_PI-a2) * d;
300         yrl = y + sin(a+M_PI-a2) * d;
301         if (!is_in_area(xrl, yrl, 0) && l_speed < 0)
302                 l_speed = 0;
303
304         xrr = x + cos(a+M_PI+a2) * d;
305         yrr = y + sin(a+M_PI+a2) * d;
306         if (!is_in_area(xrr, yrr, 0) && r_speed < 0)
307                 r_speed = 0;
308
309         xfr = x + cos(a-a2) * d;
310         yfr = y + sin(a-a2) * d;
311         if (!is_in_area(xfr, yfr, 0) && r_speed > 0)
312                 r_speed = 0;
313
314         if (pertl)
315                 l_enc += 5000; /* push 1 cm */
316         if (pertr)
317                 r_enc += 5000; /* push 1 cm */
318
319         /* XXX should lock */
320         l_enc += (l_speed / 1000);
321         r_enc += (r_speed / 1000);
322 }
323
324 void robotsim_pwm(void *arg, int32_t val)
325 {
326         //      printf("%p, %d\n", arg, val);
327         if (arg == LEFT_PWM)
328                 l_pwm = (val / 1.55);
329         else if (arg == RIGHT_PWM)
330                 r_pwm = (val / 1.55);
331 }
332
333 int32_t robotsim_encoder_get(void *arg)
334 {
335         if (arg == LEFT_ENCODER)
336                 return l_enc;
337         else if (arg == RIGHT_ENCODER)
338                 return r_enc;
339         return 0;
340 }
341
342 int robotsim_init(void)
343 {
344         mkfifo("/tmp/.robot_sim2dis", 0600);
345         mkfifo("/tmp/.robot_dis2sim", 0600);
346         fdw = open("/tmp/.robot_sim2dis", O_WRONLY, 0);
347         if (fdw < 0)
348                 return -1;
349         fdr = open("/tmp/.robot_dis2sim", O_RDONLY | O_NONBLOCK, 0);
350         if (fdr < 0) {
351                 close(fdw);
352                 return -1;
353         }
354         return 0;
355 }