Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (12.4 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
/* Globals (internal) */
28
static UserHandler user_handlers[USER_DEFINED_MSG_TOTAL];
29

    
30
static unsigned robot_x, robot_y;
31
static unsigned last_x, last_y;
32
static volatile int updated_robot_pos_ready;
33
static volatile int new_movement_command_received;
34
static volatile int robot_lost; //set to 1 if robot's position is not known by the server, else 0.
35

    
36
#define ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST (1)
37

    
38
/* Internal function prototypes */
39
static unsigned two_bytes_to_int(unsigned char high, unsigned char low);
40
static void colonet_handle_receive(char type, int source, unsigned char* packet, int length);
41
static void move_to_position_routine(unsigned x, unsigned y);
42
static int dist_squared(int x1, int y1, int x2, int y2);
43

    
44
static PacketGroupHandler colonet_pgh;
45

    
46
/* two_bytes_to_int(char a, char b)
47
 * Returns int of form [high][low]
48
 */
49
static unsigned int two_bytes_to_int(unsigned char high, unsigned char low) {
50
  return (high<<8) | low;
51
}
52

    
53
/* Public functions */
54
int colonet_init() {
55
  colonet_pgh.groupCode = COLONET_PACKET_GROUP_ID;
56
  colonet_pgh.timeout_handler = NULL;
57
  colonet_pgh.handle_response = NULL;
58
  colonet_pgh.handle_receive = colonet_handle_receive;
59
  colonet_pgh.unregister = NULL;
60

    
61
  // TODO this should return an error if wl_init has not been called yet.
62
  wl_register_packet_group(&colonet_pgh);
63

    
64
  robot_x = last_x = 0;
65
  robot_y = last_y = 0;
66
  updated_robot_pos_ready = 0;
67
  new_movement_command_received = 0;
68
  robot_lost = 1;
69

    
70
  return 0;
71
}
72

    
73
/* colonet_add_message
74
 * Adds a user-defined message
75
 */
76
int colonet_add_message(unsigned char msgId, void (*handler)(void)) {
77
  if(msgId < USER_DEFINED_MSG_ID_START  /* || msgId > USER_DEFINED_MSG_ID_END */){
78
    return -1;
79
  }
80

    
81
  /* Register this function in the array */
82
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].msgId = msgId;
83
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].handler = handler;
84

    
85
  return 0;
86
}
87

    
88
void get_absolute_position(int* x, int* y) {
89
  *x = robot_x;
90
  *y = robot_y;
91
}
92

    
93
void request_abs_position() {
94
  //usb_puts("requesting_abs_position\n");
95
  ColonetRobotServerPacket pkt;
96
  pkt.client_id = -1;
97
  pkt.msg_code = ROBOT_REQUEST_POSITION_FROM_SERVER;
98
  wl_send_global_packet(colonet_pgh.groupCode, 0, (char*)&pkt, sizeof(ColonetRobotServerPacket), 0);
99
}
100

    
101
static int dist_squared(int x1, int y1, int x2, int y2) {
102
  int dx = x1 - x2;
103
  int dy = y1 - y2;
104
  return dx*dx + dy*dy;
105
}
106

    
107
/** Differential is the intended left motor speed - right motor speed. */
108
static void set_motors_with_differential(int differential) {
109
  int ml, mr;
110

    
111
  if (differential >= 0) {
112
    /* Going left or straight. */
113
    ml = 200;
114
    mr = ml - differential;
115
  } else {
116
    /* Turning right. */
117
    mr = 200;
118
    ml = mr + differential;
119
  }
120

    
121
  int motor1_dir = mr < 0 ? 0 : 1;
122
  int motor2_dir = ml < 0 ? 0 : 1;
123

    
124
  motor1_set(motor1_dir, mr);
125
  motor2_set(motor2_dir, ml);
126
}
127

    
128
static int get_motor_differential(int e_x, int e_y, int v_x, int v_y) {
129
  //  char buf[80];
130
  //  sprintf(buf,"ex:%d ey:%d vx:%d vy:%d\n", e_x, e_y, v_x, v_y);
131
  //  usb_puts(buf);
132

    
133
  return 250;
134
  
135
  /*
136
  long e_mag = sqrt_100_approx(e_x*e_x + e_y*e_y);
137
  long v_mag = sqrt_100_approx(v_x*v_x + v_y*v_y);
138
  long e_norm_x = (1000 * e_x) / e_mag;
139
  long e_norm_y = (1000 * e_y) / e_mag;
140
  long v_norm_x = (1000 * v_x) / v_mag;
141
  long v_norm_y = (1000 * v_y) / v_mag;
142
  long e_dot_v = e_norm_x*v_norm_x + e_norm_y*v_norm_y;
143
  */
144
  
145

    
146
}
147

    
148
static void move_to_position_routine(unsigned target_x, unsigned target_y) {
149
  new_movement_command_received = 0;
150

    
151
  usb_puts("move to absolute position routine!\n");
152

    
153
  updated_robot_pos_ready = 0;
154
  request_abs_position(); // While we're doing this computation, server can be reporting next position.
155

    
156
  int count = 0;
157
  while (!updated_robot_pos_ready) {
158
    wl_do();
159
    if (count++ == 5000) { // in case the server missed it...
160
      request_abs_position();
161
      count = 0;
162
    }
163
  }
164

    
165
  int dist = 0;
166

    
167
  while (!new_movement_command_received &&
168
         (dist = dist_squared(robot_x, robot_y, target_x, target_y)) > TARGET_POSITION_STOP_DISTANCE_THRESHOLD) {
169
    char buf[80];
170
    //sprintf(buf, "dist:%d\n", dist);
171
    //usb_puts(buf);
172

    
173
    updated_robot_pos_ready = 0;
174
    request_abs_position();   // While we're doing this computation, server can be reporting next position.
175

    
176
    if (robot_lost) {
177
      usb_puts("lost known\n");
178
      motors_off();
179
    } else {
180
      // e is the error vector (where we want to go)
181
      //char buf[80];
182
      //                sprintf(buf, "target_x:%d target_y:%d robot_x:%d robot_y:%d\n", target_x, target_y, robot_x, robot_y);
183
      //                usb_puts(buf);
184

    
185
      int e_x = (int)target_x - (int)robot_x;
186
      int e_y = (int)target_y - (int)robot_y;
187

    
188
      //                sprintf(buf, "e: (x:%d,y:%d)\n", e_x, e_y);
189
      //                usb_puts(buf);
190

    
191
      // v is the velocity vector (where we just went)
192
      int v_x = (int)robot_x - (int)last_x;
193
      int v_y = (int)robot_y - (int)last_y;
194

    
195
      //sprintf(buf, "v: (x:%d,y:%d)\n", v_x, v_y);
196
      //usb_puts(buf);
197
    
198
      if (abs(v_x) < 2 && abs(v_x) < 2) {
199
        // if we didn't move since the last check, just go forward.
200
        motor1_set(1, 180);
201
        motor2_set(1, 180);
202
      } else {
203
        int e_dot_v = e_x * v_x + e_y * v_y;
204

    
205
        // move according to algortihm
206
        int e_mag = e_x*e_x + e_y*e_y;
207
        //       int motor_differential = 180;//e_mag >> 7;
208
        int motor_differential = get_motor_differential(e_x, e_y, v_x, v_y);
209

    
210
        // p is perpendicular to v, directed to the "left" of the robot.
211
        int p_x = v_y;
212
        int p_y = -v_x;
213
        int dot_product_pe = p_x * e_x + p_y * e_y;
214

    
215
        // if the dot product of p and e is negative, we should turn right. otherwise turn left.
216
        if (dot_product_pe < 0) {
217
          motor_differential = -motor_differential;
218
        }
219

    
220
        set_motors_with_differential(motor_differential);
221
      }
222
    }
223

    
224
    if (robot_lost) {
225
      motors_off();
226
    }
227

    
228
    // once we move, ask for the position again.
229
    count = 0;
230
    while (!updated_robot_pos_ready) {
231
      wl_do();
232
      if (count++ == 5000) { // in case the server missed it...
233
        request_abs_position();
234
        count = 0;
235
      }
236
    }
237
  }
238

    
239
  motors_off();
240

    
241
  //  Once this function terminates, the robot be at its destination.
242
}
243

    
244
/* Private functions */
245

    
246
/** @brief Handles colonet packets.  Should be called by parse_buffer
247
 * when it is determined that a colonet message has been received.
248
 *
249
 * @param robot_id The robot id
250
 * @param pkt_buf The packet buffer (e.g. wl_buf)
251
 *
252
 * @return -1 on error (invalid msgId), 0 on success
253
 */
254
static void colonet_handle_receive(char type, int wl_source, unsigned char* packet, int length) {
255
  length = length;
256
  wl_source = wl_source;
257

    
258
  ColonetRobotServerPacket* pkt = (ColonetRobotServerPacket*)packet;
259
  unsigned char* args; //up to 7 char args
260
  unsigned int_args[3]; //up to 3 int (2-byte) args
261
  char buf[40];
262

    
263

    
264
  /*
265
  usb_puts("Packet received.\n");
266

267
  sprintf(buf, "length=%d\n", length);
268

269
  int i;
270
  for (i = 0; i < length; i++) {
271
    sprintf(buf, "%d: %d ", i, packet[i]);
272
    usb_puts(buf);
273
 }
274
  usb_puts("\n");
275
  */
276

    
277
  //sprintf(buf, "received message from client_id=%d of length %d\n", pkt->client_id, length);
278
  //usb_puts(buf);
279

    
280
  ///assert(length == sizeof(ColonetRobotServerPacket));
281

    
282
  /*
283
  sprintf(buf, "client_id:%d, msg_code:%d\n", pkt.client_id, pkt.msg_code);
284
  usb_puts(buf);*/
285

    
286
  args = pkt->data;
287

    
288
  int_args[0] = two_bytes_to_int(args[0], args[1]);
289
  int_args[1] = two_bytes_to_int(args[2], args[3]);
290
  int_args[2] = two_bytes_to_int(args[4], args[5]);
291

    
292
  if (type == COLONET_REQUEST) {
293
    //sprintf(buf, "received colonet request: pkt msgcode is %d\n", pkt->msg_code);
294
    //usb_puts(buf);
295

    
296
    switch (pkt->msg_code) {
297
      //Sharp
298
    case READ_DISTANCE:
299
      break;
300

    
301
      //Analog
302
    case CALL_ANALOG8:
303
      break;
304
    case CALL_ANALOG10:
305
      break;
306
    case WHEEL:
307
      break;
308

    
309
    case BATTERY:
310
      sprintf((char*)pkt->data, "%d", (int)battery8());
311
      // NOTE: wl_send_robot_to_robot_global_packet does not work here!
312
      wl_send_global_packet(COLONET_PACKET_GROUP_ID, 0, (char*)pkt, sizeof(ColonetRobotServerPacket), 0);
313
      break;
314

    
315
      //BOM
316
    case GETMAXBOM:
317
      break;
318

    
319
    case DIGITAL_INPUT:
320
      break;
321
    }
322
  } else if (type == COLONET_COMMAND) {
323
    // sprintf(buf, "colonet command ... pkt->msg_code=%d\n", pkt->msg_code);
324
    // usb_puts(buf);
325

    
326
/* TODO uncomment this stuff */
327
/*     if (pkt.msg_code >= USER_DEFINED_MSG_ID_START && */
328
/*         pkt.msg_code <= USER_DEFINED_MSG_ID_END) { */
329
/*       if (user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler) { */
330
/*         /\* Call the user's handler function if it the function's address */
331
/*          * is non-zero (has been set) *\/ */
332
/*         user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler(); */
333
/*       } */
334
/*     } */
335

    
336
    switch (pkt->msg_code) {
337
/*     default: */
338
/*       printf("%s: Error - message code %d not implemented\n", __FUNCTION__, */
339
/*              pkt.msg_code); */
340
/*       break; */
341

    
342
    case SERVER_REPORT_ROBOT_LOST:
343
      last_x = robot_x;
344
      last_y = robot_y;
345

    
346
      usb_puts("lost\n");
347

    
348
      robot_lost = 1;
349

    
350
      motors_off();
351
      break;
352

    
353
    case SERVER_REPORT_POSITION_TO_ROBOT:
354
      robot_lost = 0;
355

    
356
      last_x = robot_x;
357
      last_y = robot_y;
358
      robot_x = (unsigned)int_args[0];
359
      robot_y = (unsigned)int_args[1];
360

    
361
      updated_robot_pos_ready = 1;
362

    
363
      //    sprintf(buf, "pos is: (x:%d, y:%d)\n", robot_x, robot_y);
364
      //usb_puts(buf);
365
      break;
366

    
367
    case MOVE_TO_ABSOLUTE_POSITION:
368
      new_movement_command_received = 1;
369

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

    
373
      move_to_position_routine((unsigned)int_args[0], (unsigned)int_args[1]);
374
      break;
375

    
376
      //Buzzer
377
    case BUZZER_INIT:
378
      buzzer_init();
379
      break;
380
    case BUZZER_SET_VAL:
381
      buzzer_set_val(args[0]);
382
      break;
383
    case BUZZER_SET_FREQ:
384
      buzzer_set_freq(args[0]);
385
      break;
386
    case BUZZER_CHIRP:
387
      buzzer_chirp(int_args[0], int_args[1]);
388
      break;
389
    case BUZZER_OFF:
390
      buzzer_off();
391
      break;
392

    
393
      //Orb
394
    case ORB_INIT:
395
      orb_init();
396
      break;
397
    case ORB_SET:
398
      orb_set(args[0], args[1], args[2]);
399
      break;
400
    case ORB_SET_COLOR:
401
      orb_set_color(int_args[0]);
402
      break;
403
    case ORB_DISABLE:
404
      orb_disable();
405
      break;
406
    case ORB_ENABLE:
407
      orb_enable();
408
      break;
409

    
410
      //Motors
411
    case MOTORS_INIT:
412
      usb_puts("calling motors_init\n");
413
      motors_init();
414
      break;
415
    case MOTOR1_SET:
416
      new_movement_command_received = 1;
417

    
418
      sprintf(buf, "calling motor1_set [%i] [%i]\n", args[0], args[1]);
419
      usb_puts(buf);
420
      motor1_set(args[0], args[1]);
421
      break;
422
    case MOTOR2_SET:
423
      new_movement_command_received = 1;
424

    
425
      sprintf(buf, "calling motor2_set [%i] [%i]\n", args[0], args[1]);
426
      usb_puts(buf);
427
      motor2_set(args[0], args[1]);
428
      break;
429
    case MOTORS_OFF:
430
      new_movement_command_received = 1;
431

    
432
      usb_puts("calling motors_off\n");
433
      motors_off();
434
      break;
435
    case MOVE:
436
      new_movement_command_received = 1;
437
      /* format for move: left direction, left velocity, right direction, right velocity */          
438
      sprintf(buf, "calling move\n");
439
      usb_puts(buf);
440
          motor1_set(args[0], args[1]);
441
          motor2_set(args[2], args[3]);  
442
      break;
443
    case PRINTF:
444
      usb_puts((char*)pkt->data);
445
      break;
446
    case KILL_ROBOT:
447
      new_movement_command_received = 1;
448

    
449
      motors_off();
450
      buzzer_off();
451
      exit(0); //kill the robot
452
      break;
453
    //Time
454
    case DELAY_MS:
455
      delay_ms(int_args[0]);
456
      break;
457

    
458
      //Analog
459
    case ANALOG_INIT:
460
      //TODO: how do we really init the analog? this doesn't work:
461
      //analog_init();
462
      break;
463

    
464
      //BOM
465
    case BOM_ON:
466
      bom_on();
467
      break;
468
    case BOM_OFF:
469
      bom_off();
470
      break;
471

    
472
    //Dio
473
    case DIGITAL_OUTPUT:
474
      digital_output(int_args[0], int_args[1]);
475
      break;
476
    }
477
  } else {
478
    sprintf(buf, "%s: Error: Invalid colonet message type", __FUNCTION__);
479
    usb_puts(buf);
480
  }
481
}