Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (12.5 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 (40.0)
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 volatile int updated_robot_pos_ready;
32
static volatile int new_movement_command_received;
33
#define ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST (1)
34

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

    
40
static PacketGroupHandler colonet_pgh;
41

    
42
/* two_bytes_to_int(char a, char b)
43
 * Returns int of form [high][low]
44
 */
45
static unsigned int two_bytes_to_int(unsigned char high, unsigned char low) {
46
  return (high<<8) | low;
47
}
48

    
49
/* Public functions */
50
int colonet_init() {
51
  colonet_pgh.groupCode = COLONET_PACKET_GROUP_ID;
52
  colonet_pgh.timeout_handler = NULL;
53
  colonet_pgh.handle_response = NULL;
54
  colonet_pgh.handle_receive = colonet_handle_receive;
55
  colonet_pgh.unregister = NULL;
56

    
57
  // TODO this should return an error if wl_init has not been called yet.
58
  wl_register_packet_group(&colonet_pgh);
59

    
60
  robot_x = 0;
61
  robot_y = 0;
62
  updated_robot_pos_ready = 0;
63
  new_movement_command_received = 0;
64

    
65
  return 0;
66
}
67

    
68
/* colonet_add_message
69
 * Adds a user-defined message
70
 */
71
int colonet_add_message(unsigned char msgId, void (*handler)(void)) {
72
  if(msgId < USER_DEFINED_MSG_ID_START  /* || msgId > USER_DEFINED_MSG_ID_END */){
73
    return -1;
74
  }
75

    
76
  /* Register this function in the array */
77
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].msgId = msgId;
78
  user_handlers[msgId-USER_DEFINED_MSG_ID_START].handler = handler;
79

    
80
  return 0;
81
}
82

    
83
void get_absolute_position(int* x, int* y) {
84
  *x = robot_x;
85
  *y = robot_y;
86
}
87

    
88
void request_abs_position() {
89
  //usb_puts("requesting_abs_position\n");
90

    
91
  ColonetRobotServerPacket pkt;
92
  pkt.client_id = -1;
93
  pkt.msg_code = ROBOT_REQUEST_POSITION_FROM_SERVER;
94
  wl_send_global_packet(colonet_pgh.groupCode, 0, (char*)&pkt, sizeof(ColonetRobotServerPacket), 0);
95
}
96

    
97
static float sqrt_approx(float x) {
98
  float x2 = x*x;
99
  float x3 = x*x2;
100

    
101
  return 0.00014*x3 - 0.0078*x2 + 0.29*x + 0.84;
102
}
103

    
104
static float dist(float x1, float y1, float x2, float y2) {
105
  return sqrt_approx((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
106
}
107

    
108
/* cubic approximation of arctan. */
109
/*static void arctan(float t) {
110
  float t3 = t*t*t;
111
  return -0.039 * t3 + 0.74 * t + 0.00011;
112
  }*/
113

    
114
/** Differential is the intended left motor speed - right motor speed. */
115
static void set_motors_with_differential(int differential) {
116
  int ml, mr;
117

    
118
  if (differential >= 0) {
119
    /* Going left or straight. */
120
    ml = 250;
121
    mr = ml - differential;
122
  } else {
123
    /* Turning right. */
124
    mr = 250;
125
    ml = mr + differential;
126
  }
127

    
128
  int motor1_dir = mr < 0 ? 0 : 1;
129
  int motor2_dir = ml < 0 ? 0 : 1;
130

    
131
  motor1_set(motor1_dir, mr);
132
  motor2_set(motor2_dir, ml);
133
}
134

    
135
static void move_to_position_routine(unsigned target_x, unsigned target_y) {
136
  new_movement_command_received = 0;
137

    
138
  usb_puts("move to absolute position routine!\n");
139

    
140
  updated_robot_pos_ready = 0;
141
  request_abs_position(); // While we're doing this computation, server can be reporting next position.
142

    
143
  int count = 0;
144
  while (!updated_robot_pos_ready) {
145
    wl_do();
146
    if (count++ == 5000) { // in case the server missed it...
147
      request_abs_position();
148
      count = 0;
149
    }
150
  }
151

    
152
//  usb_puts("got past first loop.\n");
153

    
154
  unsigned last_x = robot_x, last_y = robot_y;
155

    
156
  //  char buf[40];
157
  //sprintf(buf, "cur dist is %f\n", dist((float)robot_x, (float)robot_y, (float)target_x, (float)target_y));
158
  //usb_puts(buf);
159
  //sprintf(buf, "radius squared is %f\n", TARGET_POSITION_STOP_DISTANCE_THRESHOLD);
160
  //usb_puts(buf);
161

    
162
  while (!new_movement_command_received &&
163
         dist(robot_x, robot_y, target_x, target_y) > TARGET_POSITION_STOP_DISTANCE_THRESHOLD) {
164
    updated_robot_pos_ready = 0;
165
    request_abs_position(); // While we're doing this computation, server can be reporting next position.
166

    
167
//    usb_puts("after request_abs_position.\n");
168

    
169
    int cur_robot_x = robot_x;
170
    int cur_robot_y = robot_y;
171

    
172
    //usb_puts("after cur_robot_x/y = robot_x/y.\n");
173

    
174

    
175
    int e_x = target_x - cur_robot_x;
176
    int e_y = target_y - cur_robot_y;
177

    
178
    int v_x = cur_robot_x - last_x;
179
    int v_y = cur_robot_y - last_y;
180

    
181
    //    sprintf(buf, "vx:%d vy:%d rx:%d ry:%d ex:%d ey:%d\n", v_x, v_y, e_x, e_y, e_x, e_y);
182
    // usb_puts(buf);
183

    
184
    int e_mag = e_x*e_x + e_y*e_y;
185

    
186
    int motor_differential = e_mag >> 7;// / 128;
187

    
188
/*
189
    sprintf(buf, "Current position: %d %d\n", cur_robot_x, cur_robot_y);
190
    usb_puts(buf);
191

192
    sprintf(buf, "Target position: %d %d\n", target_x, target_y);
193
    usb_puts(buf);
194

195
    float r_x = (float)target_x - cur_robot_x;
196
    float r_y = (float)target_y - cur_robot_y;
197
    float r_mag = sqrt_approx(r_x * r_x + r_y * r_y);
198
    r_x /= r_mag;
199
    r_y /= r_mag;
200

201
    float v_x = (float)cur_robot_x - last_x;
202
    float v_y = robot_y - last_y;
203
    float v_mag = sqrt_approx(v_x*v_x + v_y*v_y);
204
    v_x /= v_mag;
205
    v_y /= v_mag;
206

207
    float e_x = r_x - v_x;
208
    float e_y = r_y - v_y;
209
    float e_mag = sqrt_approx(e_x * e_x + e_y * e_y);
210

211
    sprintf(buf, "Error: <%f,%f>; mag: %f\n", e_x, e_y, e_mag);
212
    usb_puts(buf);
213

214
    // Motor differential proportional to magnitude of directional error.
215
  //  int motor_differential = (int)(e_mag * ERROR_MAG_TO_MOTOR_DIFFENTIAL_CONST);
216
*/
217

    
218

    
219
    int p_x = v_y;
220
    int p_y = -v_x;
221

    
222
    int e_trans_x = p_x * e_x + p_y * e_y;
223

    
224
/*
225
    // Determine left or right by transforming error vector to robot axes
226
    // Perpendicular
227
    float p_x = v_y;
228
    float p_y = -v_x;
229

230
    // Inverse matrix
231
    float coeff = 1.0 / (p_x * v_y - v_x * p_y);
232
    float mat[2][2];
233
    mat[0][0] = v_y * coeff;
234
    mat[0][1] = -v_x * coeff;
235
    //mat[1][0] = -p_y * coeff;     //Not needed for our purposes.
236
    //mat[1][1] = p_x * coeff;
237

238
    float e_trans_x = mat[0][0] * e_x + mat[0][1] * e_y;
239
    //float e_trans_y = mat[1][0] * e_x + mat[1][1] * e_y;  //Not needed for our purposes.
240
*/
241

    
242

    
243
    if (e_trans_x < 0) {
244
      motor_differential = -motor_differential;
245
    }
246

    
247
    // sprintf(buf, "motor_diff: %d\n", motor_differential);
248
    //    usb_puts(buf);
249

    
250
    last_x = cur_robot_x;
251
    last_y = cur_robot_y;
252

    
253
    set_motors_with_differential(motor_differential);
254

    
255
    count = 0;
256
    while (!updated_robot_pos_ready) { // ghetto condition variable
257
      wl_do();
258
      if (count++ == 5000) { // in case the server missed it...
259
        request_abs_position();
260
        count = 0;
261
      }
262
    }
263
  }
264

    
265
  //  usb_puts("reached destination!\n");
266
}
267

    
268
/* Private functions */
269

    
270
/** @brief Handles colonet packets.  Should be called by parse_buffer
271
 * when it is determined that a colonet message has been received.
272
 *
273
 * @param robot_id The robot id
274
 * @param pkt_buf The packet buffer (e.g. wl_buf)
275
 *
276
 * @return -1 on error (invalid msgId), 0 on success
277
 */
278
static void colonet_handle_receive(char type, int wl_source, unsigned char* packet, int length) {
279
  length = length;
280
  wl_source = wl_source;
281

    
282
  ColonetRobotServerPacket* pkt = (ColonetRobotServerPacket*)packet;
283
  unsigned char* args; //up to 7 char args
284
  unsigned int_args[3]; //up to 3 int (2-byte) args
285
  char buf[40];
286

    
287

    
288
  /*
289
  usb_puts("Packet received.\n");
290

291
  sprintf(buf, "length=%d\n", length);
292

293
  int i;
294
  for (i = 0; i < length; i++) {
295
    sprintf(buf, "%d: %d ", i, packet[i]);
296
    usb_puts(buf);
297
 }
298
  usb_puts("\n");
299
  */
300

    
301
  //sprintf(buf, "received message from client_id=%d of length %d\n", pkt->client_id, length);
302
  //usb_puts(buf);
303

    
304
  ///assert(length == sizeof(ColonetRobotServerPacket));
305

    
306
  /*
307
  sprintf(buf, "client_id:%d, msg_code:%d\n", pkt.client_id, pkt.msg_code);
308
  usb_puts(buf);*/
309

    
310
  args = pkt->data;
311

    
312
  int_args[0] = two_bytes_to_int(args[0], args[1]);
313
  int_args[1] = two_bytes_to_int(args[2], args[3]);
314
  int_args[2] = two_bytes_to_int(args[4], args[5]);
315

    
316
  if (type == COLONET_REQUEST) {
317
    //sprintf(buf, "received colonet request: pkt msgcode is %d\n", pkt->msg_code);
318
    //usb_puts(buf);
319

    
320
    switch (pkt->msg_code) {
321
      //Sharp
322
    case READ_DISTANCE:
323
      break;
324

    
325
      //Analog
326
    case CALL_ANALOG8:
327
      break;
328
    case CALL_ANALOG10:
329
      break;
330
    case WHEEL:
331
      break;
332

    
333
    case BATTERY:
334
      sprintf((char*)pkt->data, "%d", (int)battery8());
335

    
336
      usb_puts("battery:");
337
      usb_puts((char*)pkt->data);
338
      usb_puts("\n");
339

    
340
      // NOTE: wl_send_robot_to_robot_global_packet does not work here!
341
      wl_send_global_packet(COLONET_PACKET_GROUP_ID, 0, (char*)pkt, sizeof(ColonetRobotServerPacket), 0);
342
      break;
343

    
344
      //BOM
345
    case GETMAXBOM:
346
      break;
347

    
348
    case DIGITAL_INPUT:
349
      break;
350
    }
351
  } else if (type == COLONET_COMMAND) {
352
    // sprintf(buf, "colonet command ... pkt->msg_code=%d\n", pkt->msg_code);
353
    // usb_puts(buf);
354

    
355
/* TODO uncomment this stuff */
356
/*     if (pkt.msg_code >= USER_DEFINED_MSG_ID_START && */
357
/*         pkt.msg_code <= USER_DEFINED_MSG_ID_END) { */
358
/*       if (user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler) { */
359
/*         /\* Call the user's handler function if it the function's address */
360
/*          * is non-zero (has been set) *\/ */
361
/*         user_handlers[pkt.msg_code - USER_DEFINED_MSG_ID_START].handler(); */
362
/*       } */
363
/*     } */
364

    
365
    switch (pkt->msg_code) {
366
/*     default: */
367
/*       printf("%s: Error - message code %d not implemented\n", __FUNCTION__, */
368
/*              pkt.msg_code); */
369
/*       break; */
370

    
371
    case SERVER_REPORT_POSITION_TO_ROBOT:
372
      robot_x = (unsigned)int_args[0];
373
      robot_y = (unsigned)int_args[1];
374

    
375
      updated_robot_pos_ready = 1;
376

    
377
      sprintf(buf, "pos is: %u %u\n", robot_x, robot_y);
378
      usb_puts(buf);
379
      break;
380

    
381
    case MOVE_TO_ABSOLUTE_POSITION:
382
      new_movement_command_received = 1;
383

    
384
      usb_puts("move to abs position!\n");
385
      move_to_position_routine((unsigned)int_args[0], (unsigned)int_args[1]);
386
      break;
387

    
388
      //Buzzer
389
    case BUZZER_INIT:
390
      buzzer_init();
391
      break;
392
    case BUZZER_SET_VAL:
393
      buzzer_set_val(args[0]);
394
      break;
395
    case BUZZER_SET_FREQ:
396
      buzzer_set_freq(args[0]);
397
      break;
398
    case BUZZER_CHIRP:
399
      buzzer_chirp(int_args[0], int_args[1]);
400
      break;
401
    case BUZZER_OFF:
402
      buzzer_off();
403
      break;
404

    
405
      //Orb
406
    case ORB_INIT:
407
      orb_init();
408
      break;
409
    case ORB_SET:
410
      orb_set(args[0], args[1], args[2]);
411
      break;
412
    case ORB_SET_COLOR:
413
      orb_set_color(int_args[0]);
414
      break;
415
    case ORB_DISABLE:
416
      orb_disable();
417
      break;
418
    case ORB_ENABLE:
419
      orb_enable();
420
      break;
421

    
422
      //Motors
423
    case MOTORS_INIT:
424
      usb_puts("calling motors_init\n");
425
      motors_init();
426
      break;
427
    case MOTOR1_SET:
428
      new_movement_command_received = 1;
429

    
430
      sprintf(buf, "calling motor1_set [%i] [%i]\n", args[0], args[1]);
431
      usb_puts(buf);
432
      motor1_set(args[0], args[1]);
433
      break;
434
    case MOTOR2_SET:
435
      new_movement_command_received = 1;
436

    
437
      sprintf(buf, "calling motor2_set [%i] [%i]\n", args[0], args[1]);
438
      usb_puts(buf);
439
      motor2_set(args[0], args[1]);
440
      break;
441
    case MOTORS_OFF:
442
      new_movement_command_received = 1;
443

    
444
      usb_puts("calling motors_off\n");
445
      motors_off();
446
      break;
447
    case MOVE:
448
      new_movement_command_received = 1;
449

    
450
      sprintf(buf, "calling move with: %d, %d\n", args[0], args[1]);
451
      usb_puts(buf);
452
      move(args[0], args[1]);
453
      break;
454

    
455
    case PRINTF:
456
      usb_puts((char*)pkt->data);
457
      break;
458
    case KILL_ROBOT:
459
      new_movement_command_received = 1;
460

    
461
      motors_off();
462
      buzzer_off();
463
      exit(0); //kill the robot
464
      break;
465
    //Time
466
    case DELAY_MS:
467
      delay_ms(int_args[0]);
468
      break;
469

    
470
      //Analog
471
    case ANALOG_INIT:
472
      //TODO: how do we really init the analog? this doesn't work:
473
      //analog_init();
474
      break;
475

    
476
      //BOM
477
    case BOM_ON:
478
      bom_on();
479
      break;
480
    case BOM_OFF:
481
      bom_off();
482
      break;
483

    
484
    //Dio
485
    case DIGITAL_OUTPUT:
486
      digital_output(int_args[0], int_args[1]);
487
      break;
488
    }
489
  } else {
490
    sprintf(buf, "%s: Error: Invalid colonet message type", __FUNCTION__);
491
    usb_puts(buf);
492
  }
493
}