Project

General

Profile

Statistics
| Revision:

root / branches / init_refactor / code / projects / libdragonfly / bom.c @ 1547

History | View | Annotate | Download (11.8 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26

    
27
/**
28
 * @file bom.c
29
 * @brief Implementation for using the BOM
30
 *
31
 * Contains functions for using the Bearing and Orientation Module (BOM)
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 **/
35
#include "dragonfly_defs.h"
36
#include "bom.h"
37
#include "dio.h"
38
#include "serial.h"
39
#include "analog.h"
40

    
41
//#define DEBUG_BOM_VERBOSE
42

    
43
//On the original BOM1.0, the emmitter angular order does not match the analog mux order
44
//so you need to iterate through the mux index in the following order if you want to get
45
//the detector readings in order:
46
static const char lookup[16] = {7,6,5,0xe,1,4,3,2,0xf,0,0xd,8,0xc,0xb,9,0xa};
47

    
48
// internal function prototypes
49
static void bom_select(char which);
50

    
51
/*
52
 Bk R Y (Analog)
53
---------
54
 Green
55
 Blue
56
 White
57
---------
58
 Blue
59
 White
60
*/
61

    
62

    
63
/*
64
the analog pin definitions from dio.h DO NOT work here,
65
so we must use PF0 from avrgcc (as opposed to _PIN_F0).
66
BUT the dio pin definitions from dio.h must be used (no PE...).
67

68
also, _PIN_E2 is initialized to high for some reason,
69
which turns the BOM on when the robot is turned on.
70
WORK-AROUND: call digital_output(_PIN_E2,0) at some point.
71

72
*/
73

    
74
#define MONKI PF0         //analog (yellow)
75
//------------------------//
76
#define MONKL _PIN_E2     //green
77
#define MONK1 _PIN_E3     //blue
78
#define MONK0 _PIN_E4     //white
79
//------------------------//
80
#define MONK3 _PIN_E6     //blue
81
#define MONK2 _PIN_E7     //white
82

    
83
#define BOM_VALUE_THRESHOLD 150 //200
84
#define NUM_BOM_LEDS 16
85

    
86
/*
87
  *The following pin definitions are for the BOM v1.5
88
  */
89

    
90
#define BOM_MODE        _PIN_E2        //dio0
91
#define BOM_STROBE        _PIN_E3        //dio1
92

    
93
#define BOM_DATA        _PIN_A0 //servo0
94
#define BOM_CLOCK        _PIN_A1        //servo1
95

    
96
#define BOM_S0                _PIN_E5        //dio3
97
#define BOM_S1                _PIN_E4        //dio2
98
#define BOM_S2                _PIN_E7        //dio4
99
#define BOM_S3                _PIN_E6        //dio5
100
#define BOM_OUT                PF0                //analog(yellow)
101

    
102
/**
103
 * @defgroup bom BOM (Bearing and Orientation Module)
104
 * @brief Functions for dealing with the BOM.
105
 *
106
 * The Bearing and Orientation Module / Barrel of Monkeys / BOM
107
 * is a custom sensor designed and built by the Colony Project.
108
 * It consists of a ring of 16 IR emitters and 16 IR detectors.
109
 * The BOM is most often use to determine the direction of other
110
 * robots. This module contains functions for controlling the BOM.
111
 *
112
 * Include bom.h to access these functions.
113
 *
114
 * @{
115
 **/
116

    
117
unsigned char bom_initd=0;
118

    
119
static unsigned int bom_val[NUM_BOM_LEDS];
120
static volatile char bom_type = BOM10;
121
static int select_pins[4];
122
static int analog_pin;
123

    
124
/**
125
 * Initializes the BOM.
126
 * Call bom_init before reading bom values or turning bom leds.
127
 *
128
 * @bugs INCOMPLETE - No utilization of BOM1.5 RSSI capability. Probably leave this out
129
 * until Cornell and Pras return
130
 *
131
 * @return 0 if init succesfull, an error code otherwise 
132
 *
133
 * @see bom_refresh, bom_leds_on, bom_leds_off
134
 **/
135
int bom_init(char type) {
136

    
137
  if(bom_initd) {
138
    DRAGONFLY_DEBUG_PRINT("ERROR: BOM already init'd\r\n");
139
    return ERROR_INIT_ALREADY_INITD;
140
  }
141

    
142

    
143
    bom_type = type;
144
    
145
    switch(bom_type) {
146
    case BOM10:
147
                select_pins[0] = MONK0; 
148
                select_pins[1] = MONK1;
149
                select_pins[2] = MONK2;
150
                select_pins[3] = MONK3;
151
                analog_pin = MONKI;
152
        break;
153
    case BOM15:
154
      //Sets BOM1.5 to normal [BOM] mode
155
      digital_output(BOM_MODE, 0);
156
      select_pins[0] = BOM_S0; 
157
      select_pins[1] = BOM_S1;
158
      select_pins[2] = BOM_S2;
159
      select_pins[3] = BOM_S3;
160
      bom_set_leds(BOM_ALL);
161
      analog_pin = BOM_OUT;
162
      break;
163
    case RBOM:
164
      DRAGONFLY_DEBUG_PRINT("RBOM is not currently supported\r\n");
165
        break;
166
    default:
167
      DRAGONFLY_DEBUG_PRINT("ERROR: unknown BOM type ");
168
      DRAGONFLY_DEBUG_PRINT_INT(bom_type);
169
      DRAGONFLY_DEBUG_PRINT_STR("\r\n");
170
      return -1;        
171
    //default:
172
    }
173

    
174
    bom_initd=1;
175
    return 0;
176
}
177

    
178
/**
179
 * Iterates through each bit in the bit_field. For each set bit, sets the corresponding bom select bits
180
 *    and updates the corresponding bom value with an analog_get8 reading.  analog_init and bom_init
181
 *    must be called for this to work. Must call this before reading BOM values!
182
 *
183
 *
184
 * @param bit_field specifies which elements in bom_val[] should be updated. Use BOM_ALL to refresh all values.
185
 *    Ex. if 0x0003 is passed, bom_val[0] and bom_val[1] will be updated.
186
 *
187
 * @return 0 if init succesfull, an error code otherwise
188
 *
189
 * @see bom_get
190
 **/
191
int bom_refresh(int bit_field) {
192
    int i;
193
    int loop_was_running = 0;
194

    
195
    if(!bom_initd) {
196
      DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
197
      return ERROR_LIBRARY_NOT_INITD;
198
    }
199

    
200
    
201
    //Check analog loop status
202
    if(analog_loop_status() == ADC_LOOP_RUNNING) {
203
      loop_was_running = 1;
204
      analog_stop_loop();
205
    }
206
    
207
    //Read BOM values
208
    for(i = 0; i < NUM_BOM_LEDS; i++) {
209
      if(bit_field & 0x1) {
210
        bom_select(i);
211
        bom_val[i] = analog_get8(analog_pin);
212
      }
213
      bit_field = bit_field >> 1;
214
    }
215
    
216
    //Restore analog loop status
217
    if(loop_was_running)
218
      analog_start_loop();
219

    
220
    return 0;
221
}
222

    
223
/**
224
 * Gets the bom reading from bom_val[which].  Call bom_refresh beforehand to read new bom values.
225
 *
226
 * @pre must call bom refresh first
227
 *
228
 * @param which which bom value to return
229
 *
230
 * @return the bom value, -1 on error
231
 *
232
 * see bom_refresh
233
 **/
234
int bom_get(int which) {
235
  if(!bom_initd) {
236
    DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
237
    return -1;
238
  }
239

    
240
    return bom_val[which];
241
}
242

    
243
/** 
244
 * Compares all the values in bom_val[] and returns the index to the lowest (max) value element.
245
 *
246
 * @pre must call bom refresh
247
 * @return index to the lowest (max) bom value element.  -1 if no value is lower than
248
 *    BOM_VALUE_THRESHOLD, -2 if the bom is not initialized
249
 **/
250
int bom_get_max(void) {
251
    int i, lowest_val, lowest_i;
252

    
253
    if(!bom_initd) {
254
      DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
255
      return -2;
256
    }
257

    
258
    lowest_i = -1;
259
    lowest_val = 255;
260
    for(i = 0; i < NUM_BOM_LEDS; i++) {
261
        if(bom_val[i] < lowest_val) {
262
            lowest_val = bom_val[i];
263
            lowest_i = i;
264
        }
265
    }
266
    
267
    if(lowest_val < BOM_VALUE_THRESHOLD)
268
        return lowest_i;
269
    else {
270
#ifdef DEBUG_BOM_VERBOSE
271
      DRAGONFLY_DEBUG_PRINT("ERROR: no BOM values above threshold\r\n");
272
#endif
273
        return -1;
274
    }
275
}
276

    
277
/** 
278
 * Computes the weighted average of all the bom readings to estimate the position (and distance) of another robot.
279
 *
280
 * @pre must call bom refresh
281
 * @param dist  pointer to int in which to return the estimated distance to the other robot
282
 * @return estimated position of the max bom value element as a fixed point value analogous to 10 times the
283
 *        index of the max bom value.  -1 if no value is lower than BOM_VALUE_THRESHOLD, -2 if the bom is not initialized
284
 **/
285
int bom_get_max10(int *dist) {
286
    int i, max;
287
    long long mean = 0, sum = 0;
288

    
289
    if(!bom_initd) {
290
      DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
291
      return ERROR_LIBRARY_NOT_INITD;
292
    }
293

    
294

    
295
    max = bom_get_max();
296
    if (max < 0)
297
    {
298
        if (dist)
299
        {
300
            *dist = -1;
301
        }
302
#ifdef DEBUG_BOM_VERBOSE
303
        DRAGONFLY_DEBUG_PRINT("ERROR: no BOM values above threshold\r\n");
304
#endif
305
        return -1;
306
    }
307
    /* Record values into an array */
308
    for (i = 0; i < NUM_BOM_LEDS; i++) {
309
        int idx = ((i + (NUM_BOM_LEDS/2 - max) + NUM_BOM_LEDS) % NUM_BOM_LEDS) - (NUM_BOM_LEDS/2 - max);
310
        int val = 255 - bom_val[i];
311
        mean += idx * val;
312
        sum += val;
313
    }
314
    mean = (mean * 10) / sum;
315
    mean = (mean + NUM_BOM_LEDS*10) % (NUM_BOM_LEDS*10);
316

    
317
    if (dist)
318
    {
319
        *dist = 50 - sum/48;
320
    }
321

    
322
    return mean;
323
}
324

    
325
/**
326
 * Iterates through each bit in the bit_field. If the bit is set, the corresponding emitter will
327
 *    be enabled to turn on when bom_on() is called.
328
 *    bom_init must be called for this to work. Does nothing if a BOM1.0 is installed
329
 *
330
 * @param bit_field specifies which leds should be turned on when bom_on is called.  Use BOM_ALL to turn on all bom leds.
331
 *    Ex. if 0x0005 is passed, leds 0 and 2 will be turned on.
332
 *
333
 * @return 0 if init succesfull, an error code otherwise
334
 *
335
 **/
336
int bom_set_leds(int bit_field) {
337
    int i;
338
    unsigned int mask = 1<<(NUM_BOM_LEDS-1);
339

    
340
    switch(bom_type) {
341
    case BOM10:
342
      DRAGONFLY_DEBUG_PRINT("ERROR: bom_set_leds called with a BOM 1.0. This doesn't make sense\r\n");
343
      break;
344
                
345
    case BOM15:
346
      for(i=NUM_BOM_LEDS; i>0; i--)
347
      {
348
        //set the current bit, sending MSB first
349
        digital_output(BOM_DATA, bit_field&mask);
350
        //then pulse the clock
351
        digital_output(BOM_CLOCK, 1);
352
        digital_output(BOM_CLOCK, 0);
353
        mask = mask>>1;
354
      }
355
      break;
356
                
357
    case RBOM:
358
      //add rbom code here
359
      break;
360
    }
361

    
362
    return 0;
363
}
364

    
365

    
366
/**
367
 * (DEPRECATED) Returns the direction of the maximum BOM reading,
368
 * as an integer in the range 0-15. 0 indicates to the
369
 * robot's right, while the rest of the sensors are
370
 * numbered counterclockwise. This is useful for determining
371
 * the direction of a robot flashing its BOM, of only one
372
 * robot is currently doing so. analog_init must be called
373
 * before this function can be used.
374
 *
375
 * @return the direction of the maximum BOM reading
376
 *
377
 * @see analog_init
378
 **/
379
int get_max_bom(void) {
380
    bom_refresh(BOM_ALL);
381
    return bom_get_max();
382
}
383

    
384
/**
385
 * Flashes the BOM.  If using a BOM1.5, only the emitters that have been enabled using
386
 * bom_set_leds will turn on.
387
 * 
388
 * @return 0 if init succesfull, an error code otherwise
389
 *
390
 * @see bom_off, bom_set_leds
391
 **/
392
int bom_on(void)
393
{
394
  if(!bom_initd) {
395
    DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
396
    return ERROR_LIBRARY_NOT_INITD;
397
  }
398

    
399
  switch(bom_type) {
400
  case BOM10:
401
        digital_output(MONKL, 1);
402
        break;
403
  case BOM15:
404
        digital_output(BOM_STROBE, 1);
405
        DRAGONFLY_DEBUG_PRINT("BOM should be on?\r\n");
406
        break;
407
  case RBOM:
408
        break;
409
  default:
410
    DRAGONFLY_DEBUG_PRINT("ERROR: no valid BOM type, cannot turn on\r\n");
411
    return -1;
412
  }
413

    
414
  return 0;
415
}
416

    
417
/**
418
 * Turns off all bom leds.
419
 * 
420
 * @return 0 if init succesfull, an error code otherwise
421
 *
422
 * @see bom_on
423
 **/
424
int bom_off(void)
425
{
426
  if(!bom_initd) {
427
    DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
428
    return ERROR_LIBRARY_NOT_INITD;
429
  }
430

    
431
  switch(bom_type) {
432
  case BOM10:
433
        digital_output(MONKL, 0);
434
        break;
435
  case BOM15:
436
        digital_output(BOM_STROBE, 0);
437
        break;
438
  case RBOM:
439
        break;
440
  }
441

    
442
  return 0;
443
}
444

    
445
/** @} **/ //end group
446

    
447
//select a detector to read
448
static void bom_select(char which) {
449
        if(bom_type == BOM10)
450
          which = lookup[(int)which];
451
        
452
    if (which&8)
453
      digital_output(select_pins[3], 1);
454
    else
455
      digital_output(select_pins[3], 0);
456

    
457
    if (which&4)
458
      digital_output(select_pins[2], 1);
459
    else
460
      digital_output(select_pins[2], 0);
461

    
462
    if (which&2)
463
      digital_output(select_pins[1], 1);
464
    else
465
      digital_output(select_pins[1], 0);
466

    
467
    if (which&1)
468
      digital_output(select_pins[0], 1);
469
    else
470
      digital_output(select_pins[0], 0);
471
        
472
}