Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (13.7 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 (550)
21

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

    
27
typedef struct {
28
  int up_x;
29
  int up_y;
30
  int low_x;
31
  int low_y;
32
} VirtualWall;
33

    
34
/* Globals (internal) */
35
static UserHandler user_handlers[USER_DEFINED_MSG_TOTAL];
36

    
37
static volatile unsigned robot_x, robot_y;
38
static volatile unsigned last_x, last_y;
39
static volatile int updated_robot_pos_ready;
40
static volatile int new_movement_command_received;
41
static volatile int robot_lost; //set to 1 if robot's position is not known by the server, else 0.
42
static volatile VirtualWall virtual_wall;
43

    
44
static int virtual_wall_available;
45

    
46
#define ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST (1)
47

    
48
/* Internal function prototypes */
49
static unsigned two_bytes_to_int(unsigned char high, unsigned char low);
50
static void colonet_handle_receive(char type, int source, unsigned char* packet, int length);
51
static void move_to_position_routine(unsigned x, unsigned y);
52
static int dist_squared(int x1, int y1, int x2, int y2);
53
static void move_routine(void);
54

    
55
static PacketGroupHandler colonet_pgh;
56

    
57
/* two_bytes_to_int(char a, char b)
58
 * Returns int of form [high][low]
59
 */
60
static unsigned int two_bytes_to_int(unsigned char high, unsigned char low) {
61
  return (high<<8) | low;
62
}
63

    
64
/* Public functions */
65
int colonet_init() {
66
  colonet_pgh.groupCode = COLONET_PACKET_GROUP_ID;
67
  colonet_pgh.timeout_handler = NULL;
68
  colonet_pgh.handle_response = NULL;
69
  colonet_pgh.handle_receive = colonet_handle_receive;
70
  colonet_pgh.unregister = NULL;
71

    
72
  // TODO this should return an error if wl_init has not been called yet.
73
  wl_register_packet_group(&colonet_pgh);
74

    
75
  robot_x = last_x = 0;
76
  robot_y = last_y = 0;
77
  updated_robot_pos_ready = 0;
78
  new_movement_command_received = 0;
79
  robot_lost = 1;
80

    
81
  virtual_wall_available = 0;
82
  virtual_wall.up_x = 0;
83
  virtual_wall.up_y = 0;
84
  virtual_wall.low_x = 0;
85
  virtual_wall.low_y = 0;
86

    
87
  return 0;
88
}
89

    
90
/* colonet_add_message
91
 * Adds a user-defined message
92
 */
93
int colonet_add_message(unsigned char msgId, void (*handler)(void)) {
94
  if(msgId < USER_DEFINED_MSG_ID_START  /* || msgId > USER_DEFINED_MSG_ID_END */){
95
    return -1;
96
  }
97

    
98
  /* Register this function in the array */
99
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].msgId = msgId;
100
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].handler = handler;
101

    
102
  return 0;
103
}
104

    
105
void get_absolute_position(int* x, int* y) {
106
  *x = robot_x;
107
  *y = robot_y;
108
}
109

    
110
void request_abs_position() {
111
  //usb_puts("requesting_abs_position\n");
112
  ColonetRobotServerPacket pkt;
113
  pkt.client_id = -1;
114
  pkt.msg_code = ROBOT_REQUEST_POSITION_FROM_SERVER;
115
  wl_send_global_packet(colonet_pgh.groupCode, 0, (char*)&pkt, sizeof(ColonetRobotServerPacket), 0);
116
}
117

    
118
static int dist_squared(int x1, int y1, int x2, int y2) {
119
  int dx = x1 - x2;
120
  int dy = y1 - y2;
121
  return dx*dx + dy*dy;
122
}
123

    
124
/** Differential is the intended left motor speed - right motor speed. */
125
static void set_motors_with_differential(int differential) {
126
  int ml, mr;
127

    
128
  if (differential >= 0) {
129
    /* Going left or straight. */
130
    ml = 200;
131
    mr = ml - differential;
132
  } else {
133
    /* Turning right. */
134
    mr = 200;
135
    ml = mr + differential;
136
  }
137

    
138
  int motor1_dir = mr < 0 ? 0 : 1;
139
  int motor2_dir = ml < 0 ? 0 : 1;
140

    
141
  motor1_set(motor1_dir, mr);
142
  motor2_set(motor2_dir, ml);
143
}
144

    
145
static int get_motor_differential(int e_x, int e_y, int v_x, int v_y) {
146
  //  char buf[80];
147
  //  sprintf(buf,"ex:%d ey:%d vx:%d vy:%d\n", e_x, e_y, v_x, v_y);
148
  //  usb_puts(buf);
149

    
150
  return 250;
151

    
152
  /*
153
  long e_mag = sqrt_100_approx(e_x*e_x + e_y*e_y);
154
  long v_mag = sqrt_100_approx(v_x*v_x + v_y*v_y);
155
  long e_norm_x = (1000 * e_x) / e_mag;
156
  long e_norm_y = (1000 * e_y) / e_mag;
157
  long v_norm_x = (1000 * v_x) / v_mag;
158
  long v_norm_y = (1000 * v_y) / v_mag;
159
  long e_dot_v = e_norm_x*v_norm_x + e_norm_y*v_norm_y;
160
  */
161

    
162

    
163
}
164

    
165
static void move_routine() {
166
  do {    
167
    int count = 0;
168
    while (!updated_robot_pos_ready) {
169
      wl_do();
170
      if (count++ == 5000) { // in case the server missed it...
171
        request_abs_position();
172
        count = 0;
173
      }
174
    }
175

    
176
    wl_do();
177

    
178
    if (robot_lost) {
179
      motors_off();
180
    }
181

    
182
    updated_robot_pos_ready = 0;
183
    request_abs_position();
184
  } while (!new_movement_command_received);
185
}
186

    
187
static void move_to_position_routine(unsigned target_x, unsigned target_y) {
188
  new_movement_command_received = 0;
189

    
190
  usb_puts("move to absolute position routine!\n");
191

    
192
  updated_robot_pos_ready = 0;
193
  request_abs_position(); // While we're doing this computation, server can be reporting next position.
194

    
195
  int count = 0;
196
  while (!updated_robot_pos_ready) {
197
    wl_do();
198
    if (count++ == 5000) { // in case the server missed it...
199
      request_abs_position();
200
      count = 0;
201
    }
202
  }
203

    
204
  int dist = 0;
205

    
206
  while (!new_movement_command_received &&
207
         (dist = dist_squared(robot_x, robot_y, target_x, target_y)) > TARGET_POSITION_STOP_DISTANCE_THRESHOLD) {
208
    char buf[80];
209
    //sprintf(buf, "dist:%d\n", dist);
210
    //usb_puts(buf);
211

    
212
    updated_robot_pos_ready = 0;
213
    request_abs_position();   // While we're doing this computation, server can be reporting next position.
214

    
215
    if (robot_lost) {
216
      usb_puts("lost known\n");
217
      motors_off();
218
    } else {
219
      // e is the error vector (where we want to go)
220
      //char buf[80];
221
      //                sprintf(buf, "target_x:%d target_y:%d robot_x:%d robot_y:%d\n", target_x, target_y, robot_x, robot_y);
222
      //                usb_puts(buf);
223

    
224
      int e_x = (int)target_x - (int)robot_x;
225
      int e_y = (int)target_y - (int)robot_y;
226

    
227
      //                sprintf(buf, "e: (x:%d,y:%d)\n", e_x, e_y);
228
      //                usb_puts(buf);
229

    
230
      // v is the velocity vector (where we just went)
231
      int v_x = (int)robot_x - (int)last_x;
232
      int v_y = (int)robot_y - (int)last_y;
233

    
234
      //sprintf(buf, "v: (x:%d,y:%d)\n", v_x, v_y);
235
      //usb_puts(buf);
236

    
237
      if (abs(v_x) < 2 && abs(v_x) < 2) {
238
        // if we didn't move since the last check, just go forward.
239
        motor1_set(1, 180);
240
        motor2_set(1, 180);
241
      } else {
242
        int e_dot_v = e_x * v_x + e_y * v_y;
243

    
244
        // move according to algortihm
245
        int e_mag = e_x*e_x + e_y*e_y;
246
        //       int motor_differential = 180;//e_mag >> 7;
247
        int motor_differential = get_motor_differential(e_x, e_y, v_x, v_y);
248

    
249
        // p is perpendicular to v, directed to the "left" of the robot.
250
        int p_x = v_y;
251
        int p_y = -v_x;
252
        int dot_product_pe = p_x * e_x + p_y * e_y;
253

    
254
        // if the dot product of p and e is negative, we should turn right. otherwise turn left.
255
        if (dot_product_pe < 0) {
256
          motor_differential = -motor_differential;
257
        }
258

    
259
        set_motors_with_differential(motor_differential);
260
      }
261
    }
262

    
263
    if (robot_lost) {
264
      motors_off();
265
    }
266

    
267
    // once we move, ask for the position again.
268
    count = 0;
269
    while (!updated_robot_pos_ready) {
270
      wl_do();
271
      if (count++ == 5000) { // in case the server missed it...
272
        request_abs_position();
273
        count = 0;
274
      }
275
    }
276
  }
277

    
278
  motors_off();
279

    
280
  //  Once this function terminates, the robot be at its destination.
281
}
282

    
283
/* Private functions */
284

    
285
/** @brief Handles colonet packets.  Should be called by parse_buffer
286
 * when it is determined that a colonet message has been received.
287
 *
288
 * @param robot_id The robot id
289
 * @param pkt_buf The packet buffer (e.g. wl_buf)
290
 *
291
 * @return -1 on error (invalid msgId), 0 on success
292
 */
293
static void colonet_handle_receive(char type, int wl_source, unsigned char* packet, int length) {
294
  length = length;
295
  wl_source = wl_source;
296

    
297
  ColonetRobotServerPacket* pkt = (ColonetRobotServerPacket*)packet;
298
  unsigned char* args; //up to 7 char args
299
  unsigned int_args[3]; //up to 3 int (2-byte) args
300
  char buf[40];
301

    
302

    
303
  /*
304
  usb_puts("Packet received.\n");
305

306
  sprintf(buf, "length=%d\n", length);
307

308
  int i;
309
  for (i = 0; i < length; i++) {
310
    sprintf(buf, "%d: %d ", i, packet[i]);
311
    usb_puts(buf);
312
 }
313
  usb_puts("\n");
314
  */
315

    
316
  //sprintf(buf, "received message from client_id=%d of length %d\n", pkt->client_id, length);
317
  //usb_puts(buf);
318

    
319
  ///assert(length == sizeof(ColonetRobotServerPacket));
320

    
321
  /*
322
  sprintf(buf, "client_id:%d, msg_code:%d\n", pkt.client_id, pkt.msg_code);
323
  usb_puts(buf);*/
324

    
325
  args = pkt->data;
326

    
327
  int_args[0] = two_bytes_to_int(args[0], args[1]);
328
  int_args[1] = two_bytes_to_int(args[2], args[3]);
329
  int_args[2] = two_bytes_to_int(args[4], args[5]);
330

    
331
  if (type == COLONET_REQUEST) {
332
    //sprintf(buf, "received colonet request: pkt msgcode is %d\n", pkt->msg_code);
333
    //usb_puts(buf);
334

    
335
    switch (pkt->msg_code) {
336
      //Sharp
337
    case READ_DISTANCE:
338
      break;
339

    
340
      //Analog
341
    case WHEEL:
342
      break;
343

    
344
    case BATTERY:
345
      sprintf((char*)pkt->data, "%d", (int)battery8());
346
      // NOTE: wl_send_robot_to_robot_global_packet does not work here!
347
      wl_send_global_packet(COLONET_PACKET_GROUP_ID, 0, (char*)pkt, sizeof(ColonetRobotServerPacket), 0);
348
      break;
349

    
350
      //BOM
351
    case GETMAXBOM:
352
      break;
353

    
354
    case DIGITAL_INPUT:
355
      break;
356
    }
357
  } else if (type == COLONET_COMMAND) {
358
    // sprintf(buf, "colonet command ... pkt->msg_code=%d\n", pkt->msg_code);
359
    // usb_puts(buf);
360

    
361
/* TODO uncomment this stuff */
362
/*     if (pkt.msg_code >= USER_DEFINED_MSG_ID_START && */
363
/*         pkt.msg_code <= USER_DEFINED_MSG_ID_END) { */
364
/*       if (user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler) { */
365
/*         /\* Call the user's handler function if it the function's address */
366
/*          * is non-zero (has been set) *\/ */
367
/*         user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler(); */
368
/*       } */
369
/*     } */
370

    
371
    switch (pkt->msg_code) {
372
/*     default: */
373
/*       printf("%s: Error - message code %d not implemented\n", __FUNCTION__, */
374
/*              pkt.msg_code); */
375
/*       break; */
376

    
377
    case SERVER_REPORT_ROBOT_LOST:
378
      last_x = robot_x;
379
      last_y = robot_y;
380

    
381
      usb_puts("lost\n");
382

    
383
      robot_lost = 1;
384

    
385
      motors_off();
386
      break;
387

    
388
    case SERVER_REPORT_VIRTUAL_WALL_UPPER:
389
      virtual_wall.up_x = int_args[0];
390
      virtual_wall.up_y = int_args[1];
391
      break;
392

    
393
    case SERVER_REPORT_VIRTUAL_WALL_LOWER:
394
      virtual_wall.low_x = int_args[0];
395
      virtual_wall.low_y = int_args[1];
396
      break;
397

    
398
    case SERVER_REPORT_POSITION_TO_ROBOT:
399
      robot_lost = 0;
400

    
401
      last_x = robot_x;
402
      last_y = robot_y;
403
      robot_x = (unsigned)int_args[0];
404
      robot_y = (unsigned)int_args[1];
405

    
406
      updated_robot_pos_ready = 1;
407

    
408
      if (robot_x < virtual_wall.up_x || robot_x > virtual_wall.low_x || robot_y < virtual_wall.up_x
409
          || robot_y > virtual_wall.up_y) {
410
        robot_lost = 1;
411
        motors_off();
412
      }
413

    
414
      //    sprintf(buf, "pos is: (x:%d, y:%d)\n", robot_x, robot_y);
415
      //usb_puts(buf);
416
      break;
417

    
418
    case MOVE_TO_ABSOLUTE_POSITION:
419
      new_movement_command_received = 1;
420

    
421
                        sprintf(buf, "move to abs (x:%u, y:%u)\n", (unsigned)int_args[0], (unsigned)int_args[1]);
422
                        usb_puts(buf);
423

    
424
      move_to_position_routine((unsigned)int_args[0], (unsigned)int_args[1]);
425
      break;
426

    
427
      //Buzzer
428
    case BUZZER_INIT:
429
      buzzer_init();
430
      break;
431
    case BUZZER_SET_VAL:
432
      buzzer_set_val(args[0]);
433
      break;
434
    case BUZZER_SET_FREQ:
435
      buzzer_set_freq(args[0]);
436
      break;
437
    case BUZZER_CHIRP:
438
      buzzer_chirp(int_args[0], int_args[1]);
439
      break;
440
    case BUZZER_OFF:
441
      buzzer_off();
442
      break;
443

    
444
      //Orb
445
    case ORB_INIT:
446
      orb_init();
447
      break;
448
    case ORB_SET:
449
      orb_set(args[0], args[1], args[2]);
450
      break;
451
    case ORB_SET_COLOR:
452
      orb_set_color(int_args[0]);
453
      break;
454
    case ORB_DISABLE:
455
      orb_disable();
456
      break;
457
    case ORB_ENABLE:
458
      orb_enable();
459
      break;
460

    
461
      //Motors
462
    case MOTORS_INIT:
463
      usb_puts("calling motors_init\n");
464
      motors_init();
465
      break;
466

    
467
    case MOTOR1_SET:
468
      new_movement_command_received = 1;
469

    
470
      sprintf(buf, "calling motor1_set [%i] [%i]\n", args[0], args[1]);
471
      usb_puts(buf);
472
      motor1_set(args[0], args[1]);
473
      break;
474

    
475
    case MOTOR2_SET:
476
      new_movement_command_received = 1;
477

    
478
      sprintf(buf, "calling motor2_set [%i] [%i]\n", args[0], args[1]);
479
      usb_puts(buf);
480
      motor2_set(args[0], args[1]);
481
      break;
482

    
483
    case MOTORS_OFF:
484
      new_movement_command_received = 1;
485

    
486
      usb_puts("calling motors_off\n");
487
      motors_off();
488
      break;
489

    
490
    case MOVE:
491
      new_movement_command_received = 1;
492
      /* format for move: left direction, left velocity, right direction, right velocity */
493
      sprintf(buf, "calling move\n");
494
      usb_puts(buf);
495
      motor1_set(args[0], args[1]);
496
      motor2_set(args[2], args[3]);
497

    
498
      /* Loop and update position for virtual wall. */
499
      move_routine();
500
      break;
501

    
502
    case PRINTF:
503
      usb_puts((char*)pkt->data);
504
      break;
505
    case KILL_ROBOT:
506
      new_movement_command_received = 1;
507

    
508
      motors_off();
509
      buzzer_off();
510
      exit(0); //kill the robot
511
      break;
512
    //Time
513
    case DELAY_MS:
514
      delay_ms(int_args[0]);
515
      break;
516

    
517
      //Analog
518
    case ANALOG_INIT:
519
      //TODO: how do we really init the analog? this doesn't work:
520
      //analog_init();
521
      break;
522

    
523
      //BOM
524
    case BOM_ON:
525
      bom_on();
526
      break;
527
    case BOM_OFF:
528
      bom_off();
529
      break;
530

    
531
    //Dio
532
    case DIGITAL_OUTPUT:
533
      digital_output(int_args[0], int_args[1]);
534
      break;
535
    }
536
  } else {
537
    sprintf(buf, "%s: Error: Invalid colonet message type", __FUNCTION__);
538
    usb_puts(buf);
539
  }
540
}