df8ee0ebcc2c9dac32903b6aea6c2fd47953b214
[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 /* must be called periodically */
200 void robotsim_update(void)
201 {
202         static int32_t l_pwm_shift[SHIFT];
203         static int32_t r_pwm_shift[SHIFT];
204         static int32_t l_speed, r_speed;
205         static unsigned i = 0;
206         static unsigned cpt = 0;
207
208         uint8_t flags;
209         int32_t local_l_pwm, local_r_pwm;
210         double x, y, a, a2, d;
211         char cmd[BUFSIZ];
212         int n, pertl = 0, pertr = 0;
213
214         /* corners of the robot */
215         double xfl, yfl; /* front left */
216         double xrl, yrl; /* rear left */
217         double xrr, yrr; /* rear right */
218         double xfr, yfr; /* front right */
219
220         int oppx, oppy;
221         double oppa, oppd;
222
223         /* time shift the command */
224         l_pwm_shift[i] = l_pwm;
225         r_pwm_shift[i] = r_pwm;
226         i ++;
227         i %= SHIFT;
228         local_l_pwm = l_pwm_shift[i];
229         local_r_pwm = r_pwm_shift[i];
230
231         /* read command */
232         if (((cpt ++) & 0x7) == 0) {
233                 n = read(fdr, &cmd, BUFSIZ - 1);
234                 if (n < 1)
235                         n = 0;
236                 cmd[n] = 0;
237         }
238
239         /* perturbation */
240         if (cmd[0] == 'l')
241                 pertl = 1;
242         else if (cmd[0] == 'r')
243                 pertr = 1;
244         if (cmd[0] == 'o') {
245                 if (sscanf(cmd, "opp %d %d", &oppx, &oppy) == 2) {
246                         abs_xy_to_rel_da(oppx, oppy, &oppd, &oppa);
247                         IRQ_LOCK(flags);
248                         beaconboard.oppx = oppx;
249                         beaconboard.oppy = oppy;
250                         beaconboard.oppa = DEG(oppa);
251                         if (beaconboard.oppa < 0)
252                                 beaconboard.oppa += 360;
253                         beaconboard.oppd = oppd;
254                         IRQ_UNLOCK(flags);
255                 }
256         }
257
258         x = position_get_x_double(&mainboard.pos);
259         y = position_get_y_double(&mainboard.pos);
260         a = position_get_a_rad_double(&mainboard.pos);
261
262         l_speed = ((l_speed * FILTER) / 100) +
263                 ((local_l_pwm * 1000 * FILTER2)/1000);
264         r_speed = ((r_speed * FILTER) / 100) +
265                 ((local_r_pwm * 1000 * FILTER2)/1000);
266
267         /* basic collision detection */
268         a2 = atan2(ROBOT_WIDTH/2, ROBOT_HALF_LENGTH_REAR);
269         d = norm(ROBOT_WIDTH/2, ROBOT_HALF_LENGTH_REAR);
270
271         xfl = x + cos(a+a2) * d;
272         yfl = y + sin(a+a2) * d;
273         if (!is_in_area(xfl, yfl, 0) && l_speed > 0)
274                 l_speed = 0;
275
276         xrl = x + cos(a+M_PI-a2) * d;
277         yrl = y + sin(a+M_PI-a2) * d;
278         if (!is_in_area(xrl, yrl, 0) && l_speed < 0)
279                 l_speed = 0;
280
281         xrr = x + cos(a+M_PI+a2) * d;
282         yrr = y + sin(a+M_PI+a2) * d;
283         if (!is_in_area(xrr, yrr, 0) && r_speed < 0)
284                 r_speed = 0;
285
286         xfr = x + cos(a-a2) * d;
287         yfr = y + sin(a-a2) * d;
288         if (!is_in_area(xfr, yfr, 0) && r_speed > 0)
289                 r_speed = 0;
290
291         if (pertl)
292                 l_enc += 5000; /* push 1 cm */
293         if (pertr)
294                 r_enc += 5000; /* push 1 cm */
295
296         /* XXX should lock */
297         l_enc += (l_speed / 1000);
298         r_enc += (r_speed / 1000);
299 }
300
301 void robotsim_pwm(void *arg, int32_t val)
302 {
303         //      printf("%p, %d\n", arg, val);
304         if (arg == LEFT_PWM)
305                 l_pwm = (val / 1.55);
306         else if (arg == RIGHT_PWM)
307                 r_pwm = (val / 1.55);
308 }
309
310 int32_t robotsim_encoder_get(void *arg)
311 {
312         if (arg == LEFT_ENCODER)
313                 return l_enc;
314         else if (arg == RIGHT_ENCODER)
315                 return r_enc;
316         return 0;
317 }
318
319 int robotsim_init(void)
320 {
321         mkfifo("/tmp/.robot_sim2dis", 0600);
322         mkfifo("/tmp/.robot_dis2sim", 0600);
323         fdw = open("/tmp/.robot_sim2dis", O_WRONLY, 0);
324         if (fdw < 0)
325                 return -1;
326         fdr = open("/tmp/.robot_dis2sim", O_RDONLY | O_NONBLOCK, 0);
327         if (fdr < 0) {
328                 close(fdw);
329                 return -1;
330         }
331         return 0;
332 }