Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / robot / colonet_dragonfly / colonet_dragonfly.c @ 531

History | View | Annotate | Download (11.3 KB)

1
/** @file colonet.c
2
 * @brief Colonet library for DRAGONFLY colony robots
3
 *
4
 * @author Eugene Marinelli
5
 * @date 10/10/07
6
 *
7
 * @bug Handler registration not tested
8
 * @bug Request reponding not implemented - only accepts commands.
9
 */
10

    
11
#include <assert.h>
12
#include <battery.h>
13
#include <colonet_defs.h>
14
#include <colonet_dragonfly.h>
15
#include <dragonfly_lib.h>
16
#include <math.h>
17
#include <string.h>
18
#include <wireless.h>
19

    
20
#define TARGET_POSITION_STOP_DISTANCE_THRESHOLD (15)
21

    
22
typedef struct {
23
  unsigned char msgId; //is this necessary?
24
  void (*handler)(void);
25
} UserHandler;
26

    
27
/* Globals (internal) */
28
static UserHandler user_handlers[USER_DEFINED_MSG_TOTAL];
29

    
30
static int robot_x, robot_y;
31
static volatile int updated_robot_pos_ready;
32
#define ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST (80)
33

    
34
/* Internal function prototypes */
35
static unsigned int two_bytes_to_int(char high, char low);
36
static void colonet_handle_receive(char type, int source, unsigned char* packet, int length);
37
static void move_to_position_routine(int x, int y);
38

    
39
static PacketGroupHandler colonet_pgh;
40

    
41
/* Public functions */
42
int colonet_init() {
43
  colonet_pgh.groupCode = COLONET_PACKET_GROUP_ID;
44
  colonet_pgh.timeout_handler = NULL;
45
  colonet_pgh.handle_response = NULL;
46
  colonet_pgh.handle_receive = colonet_handle_receive;
47
  colonet_pgh.unregister = NULL;
48

    
49
  // TODO this should return an error if wl_init has not been called yet.
50
  wl_register_packet_group(&colonet_pgh);
51

    
52
  robot_x = 0;
53
  robot_y = 0;
54
  updated_robot_pos_ready = 0;
55

    
56
  return 0;
57
}
58

    
59
/* colonet_add_message
60
 * Adds a user-defined message
61
 */
62
int colonet_add_message(unsigned char msgId, void (*handler)(void)) {
63
  if(msgId < USER_DEFINED_MSG_ID_START  /* || msgId > USER_DEFINED_MSG_ID_END */){
64
    return -1;
65
  }
66

    
67
  /* Register this function in the array */
68
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].msgId = msgId;
69
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].handler = handler;
70

    
71
  return 0;
72
}
73

    
74
void get_absolute_position(int* x, int* y) {
75
  *x = robot_x;
76
  *y = robot_y;
77
}
78

    
79
void request_abs_position() {
80
  usb_puts("requesting_abs_position\n");
81

    
82
  ColonetRobotServerPacket pkt;
83
  pkt.client_id = -1;
84
  pkt.msg_code = ROBOT_REQUEST_POSITION_FROM_SERVER;
85
  wl_send_global_packet(colonet_pgh.groupCode, 0, (char*)&pkt, sizeof(pkt), 0);
86
}
87

    
88
static int distsquared(int x1, int y1,int x2, int y2) {
89
  return (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
90
}
91

    
92
/* cubic approximation of arctan. */
93
/*static void arctan(float t) {
94
  float t3 = t*t*t;
95
  return -0.039 * t3 + 0.74 * t + 0.00011;
96
  }*/
97

    
98
/** Differential is the intended left motor speed - right motor speed. */
99
static void set_motors_with_differential(int differential) {
100
  int ml, mr;
101

    
102
  if (differential >= 0) {
103
    /* Going left or straight. */
104
    ml = 250;
105
    mr = ml - differential;
106
  } else {
107
    /* Turning right. */
108
    mr = 250;
109
    ml = mr + differential;
110
  }
111

    
112
  int motor1_dir = mr < 0 ? 0 : 1;
113
  int motor2_dir = ml < 0 ? 0 : 1;
114

    
115
  motor1_set(motor1_dir, mr);
116
  motor2_set(motor2_dir, ml);
117
}
118

    
119
static float sqrt_approx(float x) {
120
  float x2 = x*x;
121
  float x3 = x*x2;
122

    
123
  return 0.00014*x3 - 0.0078*x2 + 0.29*x + 0.84;
124
}
125

    
126
static void move_to_position_routine(int target_x, int target_y) {
127
  int last_x = robot_x, last_y = robot_y;
128

    
129
  char buf[40];
130
  sprintf(buf, "cur dist is %d\n", distsquared(robot_x, robot_y, target_x, target_y));
131
  usb_puts(buf);
132
  sprintf(buf, "radius squared is %d\n", TARGET_POSITION_STOP_DISTANCE_THRESHOLD*TARGET_POSITION_STOP_DISTANCE_THRESHOLD);
133
  usb_puts(buf);
134

    
135
  while (distsquared(robot_x, robot_y, target_x, target_y) >
136
        TARGET_POSITION_STOP_DISTANCE_THRESHOLD*TARGET_POSITION_STOP_DISTANCE_THRESHOLD) {
137
    request_abs_position(); // While we're doing this computation, server can be reporting next position.
138

    
139
    int count = 0;
140
    while (!updated_robot_pos_ready) { // ghetto condition variable
141
      wl_do();
142

    
143
      if (count++ == 10000) { // in case the server missed it...
144
        request_abs_position();
145
        count = 0;
146
      }
147
    }
148

    
149
    int cur_robot_x = robot_x;
150
    int cur_robot_y = robot_y;
151

    
152
    sprintf(buf, "Current position: %d %d\n", cur_robot_x, cur_robot_y);
153
    usb_puts(buf);
154

    
155
    sprintf(buf, "Target position: %d %d\n", target_x, target_y);
156
    usb_puts(buf);
157

    
158
    updated_robot_pos_ready = 0;
159
    request_abs_position(); // While we're doing this computation, server can be reporting next position.
160

    
161
    float r_x = (float)target_x - cur_robot_x;
162
    float r_y = (float)target_y - cur_robot_y;
163
    float r_mag = sqrt_approx(r_x * r_x + r_y * r_y);
164
    r_x /= r_mag;
165
    r_y /= r_mag;
166

    
167
    float v_x = (float)cur_robot_x - last_x;
168
    float v_y = robot_y - last_y;
169
    float v_mag = sqrt_approx(v_x*v_x + v_y*v_y);
170
    v_x /= v_mag;
171
    v_y /= v_mag;
172

    
173
    float e_x = r_x - v_x;
174
    float e_y = r_y - v_y;
175
    float e_mag = sqrt_approx(e_x * e_x + e_y * e_y);
176

    
177
    sprintf(buf, "Error: <%f,%f>; mag: %f\n", e_x, e_y, e_mag);
178
    usb_puts(buf);
179

    
180
    /* Motor differential proportional to magnitude of directional error. */
181
    int motor_differential = (int)(e_mag * ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST);
182

    
183
    /* Determine left or right by transforming error vector to robot axes */
184
    // Perpendicular
185
    float p_x = v_y;
186
    float p_y = -v_x;
187

    
188
    /* Inverse matrix */
189
    float coeff = 1.0 / (p_x * v_y - v_x * p_y);
190
    float mat[2][2];
191
    mat[0][0] = v_y * coeff;
192
    mat[0][1] = -v_x * coeff;
193
    //mat[1][0] = -p_y * coeff;     //Not needed for our purposes.
194
    //mat[1][1] = p_x * coeff;
195

    
196
    float e_trans_x = mat[0][0] * e_x + mat[0][1] * e_y;
197
    //float e_trans_y = mat[1][0] * e_x + mat[1][1] * e_y;  //Not needed for our purposes.
198

    
199
    if (e_trans_x < 0) {
200
      motor_differential = -motor_differential;
201
    }
202

    
203
    sprintf(buf, "motor_diff: %d\n", motor_differential);
204
    usb_puts(buf);
205

    
206
    last_x = cur_robot_x;
207
    last_y = cur_robot_y;
208

    
209
    set_motors_with_differential(motor_differential);
210
  }
211
  
212
  usb_puts("reached destination!\n");
213
}
214

    
215
/* Private functions */
216

    
217
/** @brief Handles colonet packets.  Should be called by parse_buffer
218
 * when it is determined that a colonet message has been received.
219
 *
220
 * @param robot_id The robot id
221
 * @param pkt_buf The packet buffer (e.g. wl_buf)
222
 *
223
 * @return -1 on error (invalid msgId), 0 on success
224
 */
225
static void colonet_handle_receive(char type, int wl_source, unsigned char* packet, int length) {
226
  ColonetRobotServerPacket* pkt= (ColonetRobotServerPacket*)packet;
227
  unsigned char* args; //up to 7 char args
228
  unsigned int int_args[3]; //up to 3 int (2-byte) args
229

    
230
  char buf[40];
231

    
232
  length = length;
233
  /*
234
  usb_puts("Packet received.\n");
235

236
  sprintf(buf, "length=%d\n", length);
237

238
  int i;
239
  for (i = 0; i < length; i++) {
240
    sprintf(buf, "%d: %d ", i, packet[i]);
241
    usb_puts(buf); 
242
 }
243
  usb_puts("\n");
244
  */
245

    
246
  //printf("received message from %d of length %d\n", source, length);
247

    
248
  ///assert(length == sizeof(ColonetRobotServerPacket));
249

    
250
  /*
251
  sprintf(buf, "client_id:%d, msg_code:%d\n", pkt.client_id, pkt.msg_code);
252
  usb_puts(buf);*/
253

    
254
  args = pkt->data;
255

    
256
  int_args[0] = two_bytes_to_int(args[0], args[1]);
257
  int_args[1] = two_bytes_to_int(args[2], args[3]);
258
  int_args[2] = two_bytes_to_int(args[4], args[5]);
259

    
260
  if (type == COLONET_REQUEST) {
261
    sprintf(buf, "received colonet request: pkt msgcode is %d\n", pkt->msg_code);
262
    usb_puts(buf);
263

    
264
    switch (pkt->msg_code) {
265
      //Sharp
266
    case READ_DISTANCE:
267
      break;
268
    case LINEARIZE_DISTANCE:
269
      break;
270
    case LOG_DISTANCE:
271
      break;
272

    
273
      //Analog
274
    case CALL_ANALOG8:
275
      break;
276
    case CALL_ANALOG10:
277
      break;
278
    case WHEEL:
279
      break;
280

    
281
    case BATTERY:
282
      sprintf((char*)pkt->data, "%d", (int)battery8());
283
      wl_send_robot_to_robot_global_packet(colonet_pgh.groupCode, 0, (char*)&pkt, sizeof(pkt), wl_source, 0);
284
      break;
285

    
286
      //BOM
287
    case GETMAXBOM:
288
      break;
289

    
290
      //Dio
291
    case DIGITAL_INPUT:
292
      break;
293
    case BUTTON1_READ:
294
      break;
295
    case BUTTON2_READ:
296
      break;
297

    
298
      //Bumper
299
    case DETECT_BUMP:
300
      break;
301
    }
302
  } else if (type == COLONET_COMMAND) {
303
    sprintf(buf, "colonet command ... pkt->msg_code=%d\n", pkt->msg_code);
304
    usb_puts(buf);
305

    
306
/* TODO uncomment this stuff */
307
/*     if (pkt.msg_code >= USER_DEFINED_MSG_ID_START && */
308
/*         pkt.msg_code <= USER_DEFINED_MSG_ID_END) { */
309
/*       if (user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler) { */
310
/*         /\* Call the user's handler function if it the function's address */
311
/*          * is non-zero (has been set) *\/ */
312
/*         user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler(); */
313
/*       } */
314
/*     } */
315

    
316
    switch (pkt->msg_code) {
317
/*     default: */
318
/*       printf("%s: Error - message code %d not implemented\n", __FUNCTION__, */
319
/*              pkt.msg_code); */
320
/*       break; */
321

    
322
    case SERVER_REPORT_POSITION_TO_ROBOT:
323
      robot_x = int_args[0];
324
      robot_y = int_args[1];
325

    
326
      updated_robot_pos_ready = 1;
327

    
328
      sprintf(buf, "pos is: %d %d\n", robot_x, robot_y);
329
      usb_puts(buf);
330
      break;
331

    
332
    case MOVE_TO_ABSOLUTE_POSITION:
333
      usb_puts("move to abs position2!\n");
334
      move_to_position_routine(int_args[0], int_args[1]);
335
      break;
336

    
337
      //Buzzer
338
    case BUZZER_INIT:
339
      buzzer_init();
340
      break;
341
    case BUZZER_SET_VAL:
342
      buzzer_set_val(args[0]);
343
      break;
344
    case BUZZER_SET_FREQ:
345
      buzzer_set_freq(args[0]);
346
      break;
347
    case BUZZER_CHIRP:
348
      buzzer_chirp(int_args[0], int_args[1]);
349
      break;
350
    case BUZZER_OFF:
351
      buzzer_off();
352
      break;
353
    case ORB_INIT:
354
      orb_init();
355
      break;
356
    //Orb
357
    case ORB_SET:
358
      orb_set(args[0], args[1], args[2]);
359
      break;
360
    case ORB_SET_COLOR:
361
      orb_set_color(int_args[0]);
362
      break;
363
    case ORB_DISABLE:
364
      orb_disable();
365
      break;
366
    case ORB_ENABLE:
367
      orb_enable();
368
      break;
369
    case LED_INIT:
370
      break;
371
    case LED_USER:
372
      break;
373
      //Motors
374
    case MOTORS_INIT:
375
      usb_puts("calling motors_init\n");
376
      motors_init();
377
      break;
378
    case MOTOR1_SET:
379
      sprintf(buf, "calling motor1_set [%i] [%i]\n", args[0], args[1]);
380
      usb_puts(buf);
381
      motor1_set(args[0], args[1]);
382
      break;
383
    case MOTOR2_SET:
384
      sprintf(buf, "calling motor2_set [%i] [%i]\n", args[0], args[1]);
385
      usb_puts(buf);
386
      motor2_set(args[0], args[1]);
387
      break;
388
    case MOTORS_OFF:
389
      usb_puts("calling motors_off\n");
390
      motors_off();
391
      break;
392
    case MOVE:
393
      sprintf(buf, "calling move with: %d, %d\n", args[0], args[1]);
394
      usb_puts(buf);
395
      move(args[0], args[1]);
396
      break;
397

    
398
    case USB_INIT:
399
      usb_init();
400
      break;
401

    
402
    case USB_PUTC:
403
      usb_putc((char)args[0]);
404
      break;
405

    
406
    case PRINTF:
407
      printf("%s", pkt->data);
408
      break;
409
    case KILL_ROBOT:
410
      motors_off();
411
      buzzer_off();
412
      exit(0); //kill the robot
413
      break;
414
    //Time
415
    case DELAY_MS:
416
      delay_ms(int_args[0]);
417
      break;
418

    
419
      //Analog
420
    case ANALOG_INIT:
421
      //TODO: how do we really init the analog? this doesn't work:
422
      //analog_init();
423
      break;
424

    
425
      //BOM
426
    case BOM_ON:
427
      bom_on();
428
      break;
429
    case BOM_OFF:
430
      bom_off();
431
      break;
432

    
433
    //Dio
434
    case DIGITAL_OUTPUT:
435
      digital_output(int_args[0], int_args[1]);
436
      break;
437
    }
438
  } else {
439
    sprintf(buf, "%s: Error: Invalid colonet message type", __FUNCTION__);
440
    usb_puts(buf);
441
  }
442
}
443

    
444
/* two_bytes_to_int(char a, char b)
445
 * Returns int of form [high][low]
446
 */
447
static unsigned int two_bytes_to_int(char high, char low) {
448
  return (((unsigned int)high)<<8) + (unsigned int)low;
449
}