Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / linefollowing / lineFollow.c @ 1981

History | View | Annotate | Download (10.5 KB)

1
/**
2
 * @file lineFollow.c
3
 * @defgroup lineFollwing Line Following
4
 *
5
 * Takes care of following a line. Running this program is done by calling the
6
 * init() function and then the lineFollow(speed) command.  However, direct use
7
 * of this class is discouraged as its behavior is used by lineDrive.c, which
8
 * extends this class to provide behavior functionality.
9
 *
10
 * @author Dan Jacobs and the Colony Project
11
 * @date 11-1-2010
12
 */
13

    
14
#include "lineFollow.h"
15

    
16
//! The number of bits expected in a barcode
17
#define CODESIZE 5 
18
#define LINE_COLOR 200
19

    
20

    
21
int countHi = 0;
22
int countLo = 0;
23
int maxAvg, avg;
24

    
25
// Everything has a dimension of 2 for left and right readings
26
int barCode[2][ CODESIZE ];
27
int barCodePosition[2]={0};
28

    
29
int duration[2] = {0};
30
int lastColor[2] = {0};
31
char isReset[2] = {0};
32
int lastReadings[2][ NUM_READINGS ] = {{0}};
33
int lastReadingsPtr[2] = {0};
34
int numLast[2][4] = { {0, 0, 0, NUM_READINGS}, {0, 0, 0, NUM_READINGS} };
35
int bitColor[2] = {0};
36

    
37
int turnDistance=0;
38
//! Counts the number of full line readings before we determine an intersection
39
int intersectionFilter=0;
40
int disableBarCode=0;
41

    
42
//! Keeps track of where the encoder of one motor started, for use in turns.
43
int encoderStart = -1;
44
int encoderReset = 0;   // 0 if encoderStart has no value set
45

    
46

    
47
void lineFollow_init()
48
{
49
    int i, j;
50

    
51
        analog_init(0);
52
    encoders_init();
53
        lost = 0;
54
        intersectionFilter=0;
55
        disableBarCode=0;
56

    
57
    for(i=0; i<2; i++)
58
    {
59
        for(j=0; j<NUM_READINGS; j++)
60
        {
61
            lastReadings[i][j] = BAD_READING;
62
        }
63
    }
64

    
65
    //numLast = { {0, 0, 0, NUM_READINGS}, {0, 0, 0, NUM_READINGS} };
66
}
67

    
68

    
69
/** 
70
 * Follows a line at the given speed.
71
 * @param speed The speed with which to follow the line.
72
 */
73
int lineFollow(int speed)
74
{
75
        int colors[5];
76
        int position;
77
        
78

    
79
        updateLine(colors);
80
        position = lineLocate(colors);         
81
        
82
        //not on line
83
        if(position == NOLINE)
84
        {
85
                if(lost++ > 20)
86
                {
87
                        orb2_set_color(GREEN);
88
                        motors_off();
89
                        return LINELOST;
90
                }
91
        }
92
        else if(position == FULL_LINE)
93
        {
94
                if(intersectionFilter++ > 4)
95
                {
96
                        orb2_set_color(RED);
97
                        barCodePosition[0]=0;
98
            barCodePosition[1]=0;
99
                        disableBarCode=50;
100
                }
101
        }
102
        //on line
103
        else
104
        {
105
                position*=30;
106
                orb2_set_color(ORB_OFF);
107
                motorLeft(min(speed+position, 255));
108
                motorRight(min(speed-position, 255));
109
                lost=0;
110
                intersectionFilter=0;
111
        }
112

    
113
    // If we're running over a line, stop reading barcodes for a sec
114
        if(disableBarCode-- > 0)
115
        {
116
        // Return intersection once we cross the line
117
                if(disableBarCode) return NOBARCODE;
118
                return INTERSECTION;
119
        }
120
        updateBarCode();
121
        return getBarCode();
122
}
123

    
124

    
125
/**
126
 * Implements the left merge, assuming a line exists to the left.  Works by
127
 * turning off the line at an increasing angle and waiting to hit another line
128
 * on the left.
129
 */
130
int mergeLeft()
131
{
132
        motor_l_set(FORWARD, 200);
133
        if(turnDistance!=21)motor_r_set(FORWARD, 230);
134
        else motor_r_set(FORWARD, 210);
135
        int colors[5];
136
        updateLine(colors);
137
        int position = lineLocate(colors);
138
        if(position>3 || position<-3)turnDistance++;
139

    
140
        if(turnDistance>20)
141
        {
142
        turnDistance=21;
143
        
144
                if(position<3 && position>-3)
145
                {
146
                        turnDistance = 0;
147
                        return 0;
148
                }        
149
        }
150
        return 1;
151
}
152

    
153

    
154
/**
155
 * Implements the right merge, assuming a line exists to the right.  Works by
156
 * turning off the line at an increasing angle and waiting to hit another line
157
 * on the right.
158
 */
159
int mergeRight()
160
{
161
        motor_r_set(FORWARD, 200);
162
        if(turnDistance!=21)motor_l_set(FORWARD, 230);
163
        else motor_l_set(FORWARD, 210);
164
        int colors[5];
165
        updateLine(colors);
166
        int position = lineLocate(colors);
167
        if(position>3 || position<-3)turnDistance++;
168

    
169
        if(turnDistance>20)
170
        {
171
        turnDistance=21;
172

    
173
                if(position<3 && position>-3)
174
                {
175
                        turnDistance = 0;
176
                        return 0;
177
                } 
178
        }
179
        return 1;
180
}
181

    
182

    
183

    
184
/**
185
 * Turns left at a cross of two lines.  Assumes that we are at lines in a cross
186
 * pattern, and turns until it sets straight on the new line.
187
 * @return 0 if turn finishes otherwise return 1
188
 */
189
int turnLeft()
190
{
191
        /*motor_l_set(BACKWARD, 200);
192
        motor_r_set(FORWARD, 200);
193
        int colors[5];
194
        updateLine(colors);
195
        int position = lineLocate(colors);
196
        if(position>2 || position<-2)turnDistance++;
197
        if(turnDistance>1)
198
        {
199
                if(position<3 && position>-3)
200
                {
201
                        turnDistance = 0;
202
                         return 0;
203
                }
204
        }
205
        return 1;*/
206

    
207
        motor_l_set(BACKWARD,200);
208
        motor_r_set(FORWARD,200);
209
        if(!encoderReset)
210
        {
211
            encoderStart = encoder_get_x(RIGHT);
212
            encoderReset = 1;
213
        }
214

    
215
        if(encoder_get_x(RIGHT) < encoderStart)
216
        {
217
            encoderStart = 0;
218
            // Temporary: display an "error message" in case of overflow.
219
            // Using this for debugging, take it out soon!
220
            motor_l_set(FORWARD,0);
221
            motor_r_set(FORWARD,0);
222
            //orb_set_color(WHITE);
223
            delay_ms(2000);
224
        }
225

    
226
        if(encoder_get_x(RIGHT) - encoderStart > 300)
227
        {
228
            encoderReset = 0;
229
            return 0;
230
        }
231
        return 1;
232
}
233

    
234

    
235

    
236
/**
237
 * Turns right at a cross of two lines.  Assumes that we are at lines in a cross
238
 * pattern, and turns until it sets straight on the new line.
239
 * @return 0 if the turn finishes otherwise return 1
240
 */
241
int turnRight()
242
{
243
        motor_r_set(BACKWARD, 200);
244
        motor_l_set(FORWARD, 200);
245
        int colors[5];
246
        updateLine(colors);
247
        int position = lineLocate(colors);
248
        if(position>2 || position<-2)turnDistance++;
249
        if(turnDistance>1) 
250
        {
251
                if(position<3 && position>-3)
252
                {
253
                        turnDistance = 0;
254
                         return 0;
255
                }
256
        }
257
        return 1;
258
}
259

    
260

    
261

    
262
int getBarCode()
263
{
264
        if(barCodePosition[1] != CODESIZE)
265
        return NOBARCODE ;
266
    else
267
    {
268
        int temp = 0;
269
        for(int i=0; i<CODESIZE; i++)
270
            temp += (barCode[1][i] << i);
271
        barCodePosition[1] = 0;
272
        return temp;
273
    }
274
}
275

    
276

    
277

    
278
void updateLine(int* values)
279
{        
280
        for(int i = 0; i<5; i++)
281
                values[i] = (read_line(4-i) < LINE_COLOR ? LWHITE : LBLACK);
282
}
283

    
284

    
285

    
286
int lineLocate(int* colors)
287
{
288
        int i;
289
        int wsum = 0;
290
        int count=0;
291

    
292
        for(i = 0; i<5; i++)
293
        {
294
                count += colors[i]/2;
295
                wsum += (i)*colors[i];
296
        }
297
        if(count==0)
298
                return NOLINE;        
299
        if(count==5)
300
                return FULL_LINE;
301
        return (wsum/count)-4; // Subtract 4 to center the index around the center.
302
}
303

    
304
void addToBuckets(int curColor, int i)
305
{
306
    int oldest = lastReadings[i][lastReadingsPtr[i]];
307
    numLast[i][oldest]--;
308
    lastReadings[i][lastReadingsPtr[i]] = curColor;
309
    lastReadingsPtr[i] = (lastReadingsPtr[i]+1) % NUM_READINGS;
310
    numLast[i][curColor]++;
311

    
312
    /*usb_puts("LP[");
313
    usb_puti(i);
314
    usb_puts("]: ");
315
    usb_puti(lastReadingsPtr[i]);
316
    usb_puts(", oldest: ");
317
    usb_puti(oldest);
318
    usb_puts(", Totals: ");
319

320
    for(int j=0; j<=3; j++)
321
    {
322
        usb_puts("[");
323
        usb_puti(j);
324
        usb_puts("]: ");
325
        usb_puti(numLast[i][j]);
326
        usb_puts(" ");
327
    }
328
    usb_puts("\t ");*/
329
    //usb_puts("\n");
330
}
331

    
332
void updateBarCode()
333
{
334
    // USING THESE GLOBAL VARIABLES
335
    // global int duration = 0;
336
    // global int lastColor = 0;
337
    // global int barCodePosition = 0;
338
    // global char isReset = 0;
339

    
340
    // Just uses one sensor for now
341
    for(int i = /*RIGHT*/LEFT_SENSOR; i <= LEFT_SENSOR; i++)
342
    {
343
        // Add 6 to convert left (1) and right (0) to sensor 6 and 7
344
        int curReading = read_line(i + 6);
345
        int curColor;
346

    
347
        if(curReading > BLACK_THRESHOLD)
348
        {
349
            curColor = LBLACK;
350
        }
351
        else if(curReading < GREY_THRESHOLD)
352
        {
353
            curColor = LWHITE;
354
        }
355
        else
356
        {
357
            curColor = LGREY;
358
        }
359

    
360
        /*usb_puts("Read: ");
361
        usb_puti(curReading);
362
        usb_puts("\t ");*/
363

    
364
        addToBuckets(curColor, i);
365

    
366
        // Just an error check
367
        if(barCodePosition[i] > CODESIZE)
368
        {
369
            barCodePosition[i] = 0;
370
        }
371

    
372
        // We now edit curColor to use the majority of the last buckets.
373
        if(numLast[i][1] > NUM_READINGS / 2)
374
        {
375
            curColor = LGREY;
376
        }
377
        else if(numLast[i][2] > NUM_READINGS / 2)
378
        {
379
            curColor = LBLACK;
380
        }
381
        else if(numLast[i][0] > NUM_READINGS / 2)
382
        {
383
            curColor = LWHITE;
384
            duration[i]++;
385
        }
386
        else
387
        {
388
            curColor = BAD_READING;
389
        }
390

    
391
        /*switch(curColor)
392
        {
393
            case LBLACK: usb_puts("LBLACK. "); break;
394
            case LGREY: usb_puts("LGREY. "); break;
395
            case LWHITE: usb_puts("LWHITE. "); break;
396
        }
397
        usb_puti(curReading);
398
        usb_puts("\n");*/
399
    
400
        if(curColor != BAD_READING)
401
        {
402
            // Now we assume our reading is significant - a bit, or a white space
403

    
404
            if(bitColor[i] == LGREY || bitColor[i] == LWHITE)
405
                bitColor[i] = curColor;
406

    
407
            // Only read a value if we have read 0 first (isReset == 1)
408
            if(isReset[i] && (curColor == LBLACK || curColor == LGREY) )
409
            {
410
                isReset[i] = 0;
411
                duration[i] = 0;
412
            }
413
            else if(curColor == LWHITE)
414
            {
415
                if(!isReset[i] && (bitColor[i] != LWHITE))
416
                {
417
                    barCode[i][barCodePosition[i]++] = 
418
                        (bitColor[i] == LBLACK) ? 1 : 0;
419
                    usb_puts("Reset. Read bit: ");
420
                    usb_puts(((bitColor[i] == LBLACK) ? "BLACK" : "GREY"));
421
                    usb_puts("\n");
422

    
423
                    bitColor[i] = LWHITE;
424
                }
425
                isReset[i] = 1;
426
                orb_set(0, 0, 0);
427
            }
428
        }
429

    
430
        if(curColor == LWHITE && duration[i] > TIMEOUT_DURATION 
431
            && barCodePosition[i] != 0)
432
        {
433
            usb_puts("TIMED OUT. BARCODE READER RESET.\n");
434
            usb_puts("Encoders: ");
435
            usb_puti(encoder_get_dx(LEFT));
436
            usb_puts(", ");
437
            usb_puti(encoder_get_dx(RIGHT));
438
            usb_puts("\n");
439
            barCodePosition[i] = 0;
440
            duration[i] = 0;
441
            isReset[i] = 1;
442
        }
443
    }
444
}
445

    
446

    
447
int min(int x, int y){return x>y ? y : x;}
448
int max(int x, int y){return x<y ? y : x;}
449

    
450
void motorLeft(int speed){
451
        ((speed-=127)>=0)?motor_l_set(FORWARD, 160+speed*95/128):motor_l_set(BACKWARD, 160-speed*95/127);
452
}
453

    
454
void motorRight(int speed){
455
        ((speed-=127)>=0)?motor_r_set(FORWARD, 160+speed*95/128):motor_r_set(BACKWARD, 160-speed*95/127);
456
}