Project

General

Profile

Statistics
| Revision:

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

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
        break;
165
    default:
166
      DRAGONFLY_DEBUG_PRINT("ERROR: unknown BOM type ");
167
      DRAGONFLY_DEBUG_PRINT_INT(bom_type);
168
      DRAGONFLY_DEBUG_PRINT_STR("\r\n");
169
      return -1;        
170
    //default:
171
    }
172

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

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

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

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

    
219
    return 0;
220
}
221

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

    
239
    return bom_val[which];
240
}
241

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

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

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

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

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

    
293

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

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

    
321
    return mean;
322
}
323

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

    
339
    if(!bom_initd) {
340
      DRAGONFLY_DEBUG_PRINT("ERROR: BOM not init'd\r\n");
341
      return ERROR_LIBRARY_NOT_INITD;
342
    }
343

    
344
    switch(bom_type) {
345
    case BOM10:
346
        //TODO: put an assert here to alert the user that this should not be called
347
        break;
348
                
349
    case BOM15:
350
            for(i=NUM_BOM_LEDS; i>0; i--)
351
            {
352
                    //set the current bit, sending MSB first
353
                    digital_output(BOM_DATA, bit_field&mask);
354
                    //then pulse the clock
355
                    digital_output(BOM_CLOCK, 1);
356
                    digital_output(BOM_CLOCK, 0);
357
                        mask = mask>>1;
358
            }
359
        break;
360
                
361
    case RBOM:
362
        //add rbom code here
363
        break;
364
    }
365

    
366
    return 0;
367
}
368

    
369

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

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

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

    
417
  return 0;
418
}
419

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

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

    
445
  return 0;
446
}
447

    
448
/** @} **/ //end group
449

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

    
460
    if (which&4)
461
      digital_output(select_pins[2], 1);
462
    else
463
      digital_output(select_pins[2], 0);
464

    
465
    if (which&2)
466
      digital_output(select_pins[1], 1);
467
    else
468
      digital_output(select_pins[1], 0);
469

    
470
    if (which&1)
471
      digital_output(select_pins[0], 1);
472
    else
473
      digital_output(select_pins[0], 0);
474
        
475
}